snowflake-cli-labs 2.8.0rc1__py3-none-any.whl → 3.0.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 (251) hide show
  1. snowflake/cli/__about__.py +1 -1
  2. snowflake/cli/{app → _app}/__main__.py +1 -1
  3. snowflake/cli/{app → _app}/cli_app.py +22 -13
  4. snowflake/cli/{app → _app}/commands_registration/builtin_plugins.py +15 -19
  5. snowflake/cli/{app → _app}/commands_registration/command_plugins_loader.py +9 -9
  6. snowflake/cli/{app → _app}/commands_registration/commands_registration_with_callbacks.py +4 -4
  7. snowflake/cli/{app → _app}/commands_registration/exception_logging.py +2 -2
  8. snowflake/cli/{app → _app}/commands_registration/typer_registration.py +2 -2
  9. snowflake/cli/{app → _app}/dev/docs/commands_docs_generator.py +30 -12
  10. snowflake/cli/{app → _app}/dev/docs/generator.py +3 -3
  11. snowflake/cli/{app → _app}/dev/docs/project_definition_docs_generator.py +4 -4
  12. snowflake/cli/{app → _app}/dev/docs/templates/usage.rst.jinja2 +14 -4
  13. snowflake/cli/{app → _app}/main_typer.py +2 -2
  14. snowflake/cli/{app → _app}/printing.py +2 -2
  15. snowflake/cli/_app/secret.py +9 -0
  16. snowflake/cli/{app → _app}/snow_connector.py +127 -61
  17. snowflake/cli/{app → _app}/telemetry.py +38 -7
  18. snowflake/cli/_app/version_check.py +74 -0
  19. snowflake/cli/{plugins → _plugins}/connection/commands.py +34 -11
  20. snowflake/cli/_plugins/connection/plugin_spec.py +30 -0
  21. snowflake/cli/{plugins → _plugins}/connection/util.py +16 -0
  22. snowflake/cli/{plugins → _plugins}/cortex/commands.py +54 -49
  23. snowflake/cli/{plugins → _plugins}/cortex/constants.py +1 -1
  24. snowflake/cli/{plugins → _plugins}/cortex/manager.py +5 -5
  25. snowflake/cli/{plugins → _plugins}/cortex/plugin_spec.py +1 -1
  26. snowflake/cli/{plugins → _plugins}/git/commands.py +79 -26
  27. snowflake/cli/{plugins → _plugins}/git/manager.py +72 -17
  28. snowflake/cli/{plugins → _plugins}/git/plugin_spec.py +1 -1
  29. snowflake/cli/_plugins/helpers/commands.py +90 -0
  30. snowflake/cli/{plugins/notebook → _plugins/helpers}/plugin_spec.py +1 -1
  31. snowflake/cli/{plugins → _plugins}/init/commands.py +10 -6
  32. snowflake/cli/{plugins → _plugins}/init/plugin_spec.py +1 -1
  33. snowflake/cli/{plugins → _plugins}/nativeapp/artifacts.py +24 -9
  34. snowflake/cli/_plugins/nativeapp/bundle_context.py +31 -0
  35. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/artifact_processor.py +4 -4
  36. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/compiler.py +37 -18
  37. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +249 -0
  38. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/setup/setup_driver.py.source +5 -2
  39. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/extension_function_utils.py +5 -5
  40. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/models.py +1 -1
  41. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/python_processor.py +29 -34
  42. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +114 -0
  43. snowflake/cli/{plugins → _plugins}/nativeapp/commands.py +252 -132
  44. snowflake/cli/{plugins → _plugins}/nativeapp/common_flags.py +1 -1
  45. snowflake/cli/_plugins/nativeapp/entities/application.py +878 -0
  46. snowflake/cli/_plugins/nativeapp/entities/application_package.py +1392 -0
  47. snowflake/cli/{plugins → _plugins}/nativeapp/exceptions.py +3 -12
  48. snowflake/cli/_plugins/nativeapp/manager.py +415 -0
  49. snowflake/cli/{plugins/connection → _plugins/nativeapp}/plugin_spec.py +1 -1
  50. snowflake/cli/{plugins → _plugins}/nativeapp/policy.py +3 -0
  51. snowflake/cli/{plugins → _plugins}/nativeapp/project_model.py +36 -20
  52. snowflake/cli/_plugins/nativeapp/run_processor.py +184 -0
  53. snowflake/cli/_plugins/nativeapp/same_account_install_method.py +70 -0
  54. snowflake/cli/_plugins/nativeapp/teardown_processor.py +70 -0
  55. snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +262 -0
  56. snowflake/cli/{plugins → _plugins}/nativeapp/version/commands.py +20 -49
  57. snowflake/cli/_plugins/nativeapp/version/version_processor.py +98 -0
  58. snowflake/cli/{plugins → _plugins}/notebook/commands.py +8 -6
  59. snowflake/cli/{plugins → _plugins}/notebook/manager.py +14 -14
  60. snowflake/cli/{plugins/nativeapp → _plugins/notebook}/plugin_spec.py +1 -1
  61. snowflake/cli/{plugins → _plugins}/notebook/types.py +0 -1
  62. snowflake/cli/{plugins → _plugins}/object/command_aliases.py +6 -5
  63. snowflake/cli/{plugins → _plugins}/object/commands.py +16 -10
  64. snowflake/cli/{plugins → _plugins}/object/manager.py +43 -21
  65. snowflake/cli/{plugins → _plugins}/object/plugin_spec.py +1 -1
  66. snowflake/cli/_plugins/snowpark/commands.py +450 -0
  67. snowflake/cli/_plugins/snowpark/common.py +268 -0
  68. snowflake/cli/{plugins → _plugins}/snowpark/models.py +2 -8
  69. snowflake/cli/{plugins → _plugins}/snowpark/package/anaconda_packages.py +2 -36
  70. snowflake/cli/{plugins → _plugins}/snowpark/package/commands.py +13 -74
  71. snowflake/cli/{plugins → _plugins}/snowpark/package/manager.py +4 -3
  72. snowflake/cli/{plugins → _plugins}/snowpark/package_utils.py +5 -5
  73. snowflake/cli/_plugins/snowpark/plugin_spec.py +30 -0
  74. snowflake/cli/_plugins/snowpark/snowpark_entity.py +29 -0
  75. snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +173 -0
  76. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +109 -0
  77. snowflake/cli/{plugins → _plugins}/snowpark/snowpark_shared.py +0 -36
  78. snowflake/cli/{plugins → _plugins}/snowpark/zipper.py +16 -8
  79. snowflake/cli/{plugins → _plugins}/spcs/__init__.py +5 -7
  80. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/commands.py +29 -28
  81. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/manager.py +3 -3
  82. snowflake/cli/{plugins → _plugins}/spcs/image_registry/commands.py +3 -3
  83. snowflake/cli/{plugins → _plugins}/spcs/image_repository/commands.py +25 -19
  84. snowflake/cli/{plugins → _plugins}/spcs/image_repository/manager.py +1 -1
  85. snowflake/cli/{plugins → _plugins}/spcs/plugin_spec.py +1 -1
  86. snowflake/cli/{plugins → _plugins}/spcs/services/commands.py +66 -32
  87. snowflake/cli/{plugins → _plugins}/spcs/services/manager.py +43 -5
  88. snowflake/cli/{plugins → _plugins}/sql/commands.py +20 -17
  89. snowflake/cli/{plugins → _plugins}/sql/manager.py +1 -1
  90. snowflake/cli/{plugins → _plugins}/sql/plugin_spec.py +1 -1
  91. snowflake/cli/{plugins → _plugins}/stage/commands.py +20 -17
  92. snowflake/cli/{plugins → _plugins}/stage/diff.py +1 -47
  93. snowflake/cli/{plugins → _plugins}/stage/manager.py +62 -24
  94. snowflake/cli/{plugins → _plugins}/stage/plugin_spec.py +1 -1
  95. snowflake/cli/_plugins/stage/utils.py +54 -0
  96. snowflake/cli/{plugins → _plugins}/streamlit/commands.py +71 -62
  97. snowflake/cli/{plugins → _plugins}/streamlit/manager.py +68 -70
  98. snowflake/cli/_plugins/streamlit/plugin_spec.py +30 -0
  99. snowflake/cli/_plugins/streamlit/streamlit_entity.py +12 -0
  100. snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +66 -0
  101. snowflake/cli/_plugins/workspace/action_context.py +18 -0
  102. snowflake/cli/_plugins/workspace/commands.py +306 -0
  103. snowflake/cli/_plugins/workspace/manager.py +74 -0
  104. snowflake/cli/_plugins/workspace/plugin_spec.py +30 -0
  105. snowflake/cli/api/cli_global_context.py +152 -295
  106. snowflake/cli/api/commands/common.py +25 -0
  107. snowflake/cli/api/commands/decorators.py +19 -4
  108. snowflake/cli/api/commands/experimental_behaviour.py +2 -3
  109. snowflake/cli/api/commands/flags.py +143 -222
  110. snowflake/cli/api/commands/overrideable_parameter.py +143 -0
  111. snowflake/cli/api/commands/snow_typer.py +21 -11
  112. snowflake/cli/api/commands/utils.py +18 -0
  113. snowflake/cli/api/config.py +44 -12
  114. snowflake/cli/api/connections.py +216 -0
  115. snowflake/cli/api/console/abc.py +8 -3
  116. snowflake/cli/api/constants.py +11 -0
  117. snowflake/cli/api/entities/common.py +56 -0
  118. snowflake/cli/api/entities/utils.py +370 -0
  119. snowflake/cli/api/errno.py +1 -0
  120. snowflake/cli/api/exceptions.py +31 -5
  121. snowflake/cli/api/feature_flags.py +0 -1
  122. snowflake/cli/api/identifiers.py +45 -9
  123. snowflake/cli/api/metrics.py +92 -0
  124. snowflake/cli/api/project/definition.py +48 -6
  125. snowflake/cli/api/project/definition_conversion.py +400 -0
  126. snowflake/cli/api/project/definition_manager.py +16 -5
  127. snowflake/cli/api/project/project_verification.py +3 -3
  128. snowflake/cli/api/project/schemas/entities/common.py +91 -16
  129. snowflake/cli/api/project/schemas/entities/entities.py +37 -6
  130. snowflake/cli/api/project/schemas/project_definition.py +180 -49
  131. snowflake/cli/api/project/schemas/updatable_model.py +11 -3
  132. snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
  133. snowflake/cli/api/project/schemas/{identifier_model.py → v1/identifier_model.py} +3 -1
  134. snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
  135. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/application.py +8 -9
  136. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/native_app.py +4 -4
  137. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/package.py +7 -1
  138. snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
  139. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/callable.py +2 -2
  140. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/snowpark.py +2 -2
  141. snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
  142. snowflake/cli/api/project/schemas/{streamlit → v1/streamlit}/streamlit.py +2 -1
  143. snowflake/cli/api/project/util.py +23 -6
  144. snowflake/cli/api/rendering/jinja.py +14 -8
  145. snowflake/cli/api/rendering/project_definition_templates.py +5 -1
  146. snowflake/cli/api/rendering/sql_templates.py +56 -11
  147. snowflake/cli/api/rest_api.py +11 -5
  148. snowflake/cli/api/secure_path.py +16 -18
  149. snowflake/cli/api/secure_utils.py +90 -1
  150. snowflake/cli/api/sql_execution.py +47 -27
  151. snowflake/cli/api/utils/definition_rendering.py +45 -13
  152. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/METADATA +20 -18
  153. snowflake_cli_labs-3.0.0.dist-info/RECORD +242 -0
  154. snowflake_cli_labs-3.0.0.dist-info/entry_points.txt +2 -0
  155. snowflake/cli/api/commands/project_initialisation.py +0 -65
  156. snowflake/cli/api/commands/typer_pre_execute.py +0 -26
  157. snowflake/cli/api/project/schemas/entities/application_entity.py +0 -44
  158. snowflake/cli/api/project/schemas/entities/application_package_entity.py +0 -66
  159. snowflake/cli/app/build_and_push.sh +0 -8
  160. snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -172
  161. snowflake/cli/plugins/nativeapp/init.py +0 -345
  162. snowflake/cli/plugins/nativeapp/manager.py +0 -823
  163. snowflake/cli/plugins/nativeapp/run_processor.py +0 -389
  164. snowflake/cli/plugins/nativeapp/teardown_processor.py +0 -301
  165. snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +0 -135
  166. snowflake/cli/plugins/nativeapp/version/version_processor.py +0 -362
  167. snowflake/cli/plugins/object_stage_deprecated/__init__.py +0 -15
  168. snowflake/cli/plugins/object_stage_deprecated/commands.py +0 -122
  169. snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +0 -32
  170. snowflake/cli/plugins/snowpark/commands.py +0 -548
  171. snowflake/cli/plugins/snowpark/common.py +0 -307
  172. snowflake/cli/plugins/snowpark/manager.py +0 -109
  173. snowflake/cli/plugins/snowpark/plugin_spec.py +0 -30
  174. snowflake/cli/plugins/snowpark/snowpark_package_paths.py +0 -65
  175. snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
  176. snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
  177. snowflake/cli/plugins/streamlit/__init__.py +0 -13
  178. snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
  179. snowflake/cli/plugins/workspace/__init__.py +0 -13
  180. snowflake/cli/plugins/workspace/commands.py +0 -35
  181. snowflake/cli/plugins/workspace/plugin_spec.py +0 -30
  182. snowflake/cli/templates/default_snowpark/.gitignore +0 -4
  183. snowflake/cli/templates/default_snowpark/app/common.py +0 -2
  184. snowflake/cli/templates/default_snowpark/app/functions.py +0 -15
  185. snowflake/cli/templates/default_snowpark/app/procedures.py +0 -22
  186. snowflake/cli/templates/default_snowpark/requirements.txt +0 -1
  187. snowflake/cli/templates/default_snowpark/snowflake.yml +0 -23
  188. snowflake/cli/templates/default_streamlit/.gitignore +0 -4
  189. snowflake/cli/templates/default_streamlit/common/hello.py +0 -2
  190. snowflake/cli/templates/default_streamlit/environment.yml +0 -6
  191. snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -3
  192. snowflake/cli/templates/default_streamlit/snowflake.yml +0 -10
  193. snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -4
  194. snowflake_cli_labs-2.8.0rc1.dist-info/RECORD +0 -240
  195. snowflake_cli_labs-2.8.0rc1.dist-info/entry_points.txt +0 -2
  196. /snowflake/cli/{app → _app}/__init__.py +0 -0
  197. /snowflake/cli/{api/project/schemas/native_app → _app/api_impl}/__init__.py +0 -0
  198. /snowflake/cli/{api/project/schemas/snowpark → _app/api_impl/plugin}/__init__.py +0 -0
  199. /snowflake/cli/{app → _app}/api_impl/plugin/plugin_config_provider_impl.py +0 -0
  200. /snowflake/cli/{app → _app}/commands_registration/__init__.py +0 -0
  201. /snowflake/cli/{app → _app}/commands_registration/threadsafe.py +0 -0
  202. /snowflake/cli/{app → _app}/constants.py +0 -0
  203. /snowflake/cli/{api/project/schemas/streamlit → _app/dev}/__init__.py +0 -0
  204. /snowflake/cli/{app → _app}/dev/commands_structure.py +0 -0
  205. /snowflake/cli/{app/api_impl → _app/dev/docs}/__init__.py +0 -0
  206. /snowflake/cli/{app → _app}/dev/docs/project_definition_generate_json_schema.py +0 -0
  207. /snowflake/cli/{app → _app}/dev/docs/template_utils.py +0 -0
  208. /snowflake/cli/{app → _app}/dev/docs/templates/definition_description.rst.jinja2 +0 -0
  209. /snowflake/cli/{app → _app}/dev/docs/templates/overview.rst.jinja2 +0 -0
  210. /snowflake/cli/{app → _app}/dev/pycharm_remote_debug.py +0 -0
  211. /snowflake/cli/{app → _app}/loggers.py +0 -0
  212. /snowflake/cli/{app/api_impl/plugin → _plugins}/__init__.py +0 -0
  213. /snowflake/cli/{app/dev → _plugins/connection}/__init__.py +0 -0
  214. /snowflake/cli/{app/dev/docs → _plugins/cortex}/__init__.py +0 -0
  215. /snowflake/cli/{plugins → _plugins}/cortex/types.py +0 -0
  216. /snowflake/cli/{plugins → _plugins/git}/__init__.py +0 -0
  217. /snowflake/cli/{plugins/connection → _plugins/helpers}/__init__.py +0 -0
  218. /snowflake/cli/{plugins/cortex → _plugins/init}/__init__.py +0 -0
  219. /snowflake/cli/{plugins/git → _plugins/nativeapp}/__init__.py +0 -0
  220. /snowflake/cli/{plugins/init → _plugins/nativeapp/codegen}/__init__.py +0 -0
  221. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/sandbox.py +0 -0
  222. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -0
  223. /snowflake/cli/{plugins → _plugins}/nativeapp/constants.py +0 -0
  224. /snowflake/cli/{templates/default_snowpark/app → _plugins/nativeapp/entities}/__init__.py +0 -0
  225. /snowflake/cli/{plugins → _plugins}/nativeapp/feature_flags.py +0 -0
  226. /snowflake/cli/{plugins → _plugins}/nativeapp/utils.py +0 -0
  227. /snowflake/cli/{plugins/nativeapp → _plugins/nativeapp/version}/__init__.py +0 -0
  228. /snowflake/cli/{plugins/nativeapp/codegen → _plugins/notebook}/__init__.py +0 -0
  229. /snowflake/cli/{plugins → _plugins}/notebook/exceptions.py +0 -0
  230. /snowflake/cli/{plugins/nativeapp/version → _plugins/object}/__init__.py +0 -0
  231. /snowflake/cli/{plugins → _plugins}/object/common.py +0 -0
  232. /snowflake/cli/{plugins/notebook → _plugins/snowpark}/__init__.py +0 -0
  233. /snowflake/cli/{plugins/object → _plugins/snowpark/package}/__init__.py +0 -0
  234. /snowflake/cli/{plugins → _plugins}/snowpark/package/utils.py +0 -0
  235. /snowflake/cli/{plugins → _plugins}/spcs/common.py +0 -0
  236. /snowflake/cli/{plugins/snowpark → _plugins/spcs/compute_pool}/__init__.py +0 -0
  237. /snowflake/cli/{plugins/snowpark/package → _plugins/spcs/image_registry}/__init__.py +0 -0
  238. /snowflake/cli/{plugins → _plugins}/spcs/image_registry/manager.py +0 -0
  239. /snowflake/cli/{plugins/spcs/compute_pool → _plugins/spcs/image_repository}/__init__.py +0 -0
  240. /snowflake/cli/{plugins/spcs/image_registry → _plugins/spcs/services}/__init__.py +0 -0
  241. /snowflake/cli/{plugins/spcs/image_repository → _plugins/sql}/__init__.py +0 -0
  242. /snowflake/cli/{plugins → _plugins}/sql/snowsql_templating.py +0 -0
  243. /snowflake/cli/{plugins/spcs/jobs → _plugins/stage}/__init__.py +0 -0
  244. /snowflake/cli/{plugins → _plugins}/stage/md5.py +0 -0
  245. /snowflake/cli/{plugins/spcs/services → _plugins/streamlit}/__init__.py +0 -0
  246. /snowflake/cli/{plugins/sql → _plugins/workspace}/__init__.py +0 -0
  247. /snowflake/cli/{plugins/stage → api/project/schemas/entities}/__init__.py +0 -0
  248. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/path_mapping.py +0 -0
  249. /snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/argument.py +0 -0
  250. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/WHEEL +0 -0
  251. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,389 +0,0 @@
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
- from pathlib import Path
18
- from textwrap import dedent
19
- from typing import Optional
20
-
21
- import typer
22
- from click import UsageError
23
- from snowflake.cli.api.console import cli_console as cc
24
- from snowflake.cli.api.errno import (
25
- APPLICATION_NO_LONGER_AVAILABLE,
26
- APPLICATION_OWNS_EXTERNAL_OBJECTS,
27
- CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION,
28
- CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES,
29
- NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
30
- ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
31
- )
32
- from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
33
- from snowflake.cli.api.project.schemas.native_app.native_app import NativeApp
34
- from snowflake.cli.api.project.util import (
35
- identifier_to_show_like_pattern,
36
- unquote_identifier,
37
- )
38
- from snowflake.cli.api.utils.cursor import find_all_rows
39
- from snowflake.cli.plugins.nativeapp.artifacts import BundleMap
40
- from snowflake.cli.plugins.nativeapp.constants import (
41
- ALLOWED_SPECIAL_COMMENTS,
42
- COMMENT_COL,
43
- PATCH_COL,
44
- SPECIAL_COMMENT,
45
- VERSION_COL,
46
- )
47
- from snowflake.cli.plugins.nativeapp.exceptions import (
48
- ApplicationCreatedExternallyError,
49
- ApplicationPackageDoesNotExistError,
50
- )
51
- from snowflake.cli.plugins.nativeapp.manager import (
52
- NativeAppCommandProcessor,
53
- NativeAppManager,
54
- ensure_correct_owner,
55
- generic_sql_error_handler,
56
- )
57
- from snowflake.cli.plugins.nativeapp.policy import PolicyBase
58
- from snowflake.cli.plugins.nativeapp.project_model import (
59
- NativeAppProjectModel,
60
- )
61
- from snowflake.cli.plugins.stage.manager import StageManager
62
- from snowflake.connector import ProgrammingError
63
- from snowflake.connector.cursor import DictCursor, SnowflakeCursor
64
-
65
- # Reasons why an `alter application ... upgrade` might fail
66
- UPGRADE_RESTRICTION_CODES = {
67
- CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION,
68
- CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES,
69
- ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
70
- NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
71
- APPLICATION_NO_LONGER_AVAILABLE,
72
- }
73
-
74
-
75
- def print_messages(create_or_upgrade_cursor: Optional[SnowflakeCursor]):
76
- """
77
- Shows messages in the console returned by the CREATE or UPGRADE
78
- APPLICATION command.
79
- """
80
- if not create_or_upgrade_cursor:
81
- return
82
-
83
- messages = [row[0] for row in create_or_upgrade_cursor.fetchall()]
84
- for message in messages:
85
- cc.warning(message)
86
- cc.message("")
87
-
88
-
89
- class SameAccountInstallMethod:
90
- _requires_created_by_cli: bool
91
- _from_release_directive: bool
92
- version: Optional[str]
93
- patch: Optional[int]
94
-
95
- def __init__(
96
- self,
97
- requires_created_by_cli: bool,
98
- version: Optional[str] = None,
99
- patch: Optional[int] = None,
100
- from_release_directive: bool = False,
101
- ):
102
- self._requires_created_by_cli = requires_created_by_cli
103
- self.version = version
104
- self.patch = patch
105
- self._from_release_directive = from_release_directive
106
-
107
- @classmethod
108
- def unversioned_dev(cls):
109
- """aka. stage dev aka loose files"""
110
- return cls(True)
111
-
112
- @classmethod
113
- def versioned_dev(cls, version: str, patch: Optional[int] = None):
114
- return cls(False, version, patch)
115
-
116
- @classmethod
117
- def release_directive(cls):
118
- return cls(False, from_release_directive=True)
119
-
120
- @property
121
- def is_dev_mode(self) -> bool:
122
- return not self._from_release_directive
123
-
124
- def using_clause(self, app: NativeAppProjectModel) -> str:
125
- if self._from_release_directive:
126
- return ""
127
-
128
- if self.version:
129
- patch_clause = f"patch {self.patch}" if self.patch else ""
130
- return f"using version {self.version} {patch_clause}"
131
-
132
- stage_name = StageManager.quote_stage_name(app.stage_fqn)
133
- return f"using {stage_name}"
134
-
135
- def ensure_app_usable(self, app: NativeAppProjectModel, show_app_row: dict):
136
- """Raise an exception if we cannot proceed with install given the pre-existing application object"""
137
-
138
- if self._requires_created_by_cli:
139
- if show_app_row[COMMENT_COL] not in ALLOWED_SPECIAL_COMMENTS:
140
- # this application object was not created by this tooling
141
- raise ApplicationCreatedExternallyError(app.app_name)
142
-
143
- # expected owner
144
- ensure_correct_owner(row=show_app_row, role=app.app_role, obj_name=app.app_name)
145
-
146
-
147
- class NativeAppRunProcessor(NativeAppManager, NativeAppCommandProcessor):
148
- def __init__(self, project_definition: NativeApp, project_root: Path):
149
- super().__init__(project_definition, project_root)
150
-
151
- def get_all_existing_versions(self) -> SnowflakeCursor:
152
- """
153
- Get all existing versions, if defined, for an application package.
154
- It executes a 'show versions in application package' query and returns all the results.
155
- """
156
- with self.use_role(self.package_role):
157
- show_obj_query = f"show versions in application package {self.package_name}"
158
- show_obj_cursor = self._execute_query(show_obj_query)
159
-
160
- if show_obj_cursor.rowcount is None:
161
- raise SnowflakeSQLExecutionError(show_obj_query)
162
-
163
- return show_obj_cursor
164
-
165
- def get_existing_version_info(self, version: str) -> Optional[dict]:
166
- """
167
- Get the latest patch on an existing version by name in the application package.
168
- Executes 'show versions like ... in application package' query and returns
169
- the latest patch in the version as a single row, if one exists. Otherwise,
170
- returns None.
171
- """
172
- with self.use_role(self.package_role):
173
- try:
174
- query = f"show versions like {identifier_to_show_like_pattern(version)} in application package {self.package_name}"
175
- cursor = self._execute_query(query, cursor_class=DictCursor)
176
-
177
- if cursor.rowcount is None:
178
- raise SnowflakeSQLExecutionError(query)
179
-
180
- matching_rows = find_all_rows(
181
- cursor, lambda row: row[VERSION_COL] == unquote_identifier(version)
182
- )
183
-
184
- if not matching_rows:
185
- return None
186
-
187
- return max(matching_rows, key=lambda row: row[PATCH_COL])
188
-
189
- except ProgrammingError as err:
190
- if err.msg.__contains__("does not exist or not authorized"):
191
- raise ApplicationPackageDoesNotExistError(self.package_name)
192
- else:
193
- generic_sql_error_handler(err=err, role=self.package_role)
194
- return None
195
-
196
- def drop_application_before_upgrade(
197
- self, policy: PolicyBase, is_interactive: bool, cascade: bool = False
198
- ):
199
- """
200
- This method will attempt to drop an application object if a previous upgrade fails.
201
- """
202
- if cascade:
203
- try:
204
- if application_objects := self.get_objects_owned_by_application():
205
- application_objects_str = self._application_objects_to_str(
206
- application_objects
207
- )
208
- cc.message(
209
- f"The following objects are owned by application {self.app_name} and need to be dropped:\n{application_objects_str}"
210
- )
211
- except ProgrammingError as err:
212
- if err.errno != APPLICATION_NO_LONGER_AVAILABLE:
213
- generic_sql_error_handler(err)
214
- cc.warning(
215
- "The application owns other objects but they could not be determined."
216
- )
217
- user_prompt = "Do you want the Snowflake CLI to drop these objects, then drop the existing application object and recreate it?"
218
- else:
219
- user_prompt = "Do you want the Snowflake CLI to drop the existing application object and recreate it?"
220
-
221
- if not policy.should_proceed(user_prompt):
222
- if is_interactive:
223
- cc.message("Not upgrading the application object.")
224
- raise typer.Exit(0)
225
- else:
226
- cc.message(
227
- "Cannot upgrade the application object non-interactively without --force."
228
- )
229
- raise typer.Exit(1)
230
- try:
231
- cascade_msg = " (cascade)" if cascade else ""
232
- cc.step(f"Dropping application object {self.app_name}{cascade_msg}.")
233
- cascade_sql = " cascade" if cascade else ""
234
- self._execute_query(f"drop application {self.app_name}{cascade_sql}")
235
- except ProgrammingError as err:
236
- if err.errno == APPLICATION_OWNS_EXTERNAL_OBJECTS and not cascade:
237
- # We need to cascade the deletion, let's try again (only if we didn't try with cascade already)
238
- return self.drop_application_before_upgrade(
239
- policy, is_interactive, cascade=True
240
- )
241
- else:
242
- generic_sql_error_handler(err)
243
-
244
- def create_or_upgrade_app(
245
- self,
246
- policy: PolicyBase,
247
- install_method: SameAccountInstallMethod,
248
- is_interactive: bool = False,
249
- ):
250
- with self.use_role(self.app_role):
251
-
252
- # 1. Need to use a warehouse to create an application object
253
- with self.use_warehouse(self.application_warehouse):
254
-
255
- # 2. Check for an existing application by the same name
256
- show_app_row = self.get_existing_app_info()
257
-
258
- # 3. If existing application is found, perform a few validations and upgrade the application object.
259
- if show_app_row:
260
-
261
- install_method.ensure_app_usable(self._na_project, show_app_row)
262
-
263
- # If all the above checks are in order, proceed to upgrade
264
- try:
265
- cc.step(
266
- f"Upgrading existing application object {self.app_name}."
267
- )
268
- using_clause = install_method.using_clause(self._na_project)
269
- upgrade_cursor = self._execute_query(
270
- f"alter application {self.app_name} upgrade {using_clause}",
271
- )
272
- print_messages(upgrade_cursor)
273
-
274
- if install_method.is_dev_mode:
275
- # if debug_mode is present (controlled), ensure it is up-to-date
276
- if self.debug_mode is not None:
277
- self._execute_query(
278
- f"alter application {self.app_name} set debug_mode = {self.debug_mode}"
279
- )
280
-
281
- # hooks always executed after a create or upgrade
282
- self.execute_app_post_deploy_hooks()
283
- return
284
-
285
- except ProgrammingError as err:
286
- if err.errno not in UPGRADE_RESTRICTION_CODES:
287
- generic_sql_error_handler(err=err)
288
- else: # The existing application object was created from a different process.
289
- cc.warning(err.msg)
290
- self.drop_application_before_upgrade(policy, is_interactive)
291
-
292
- # 4. With no (more) existing application objects, create an application object using the release directives
293
- cc.step(f"Creating new application object {self.app_name} in account.")
294
-
295
- if self.app_role != self.package_role:
296
- with self.use_role(self.package_role):
297
- self._execute_query(
298
- f"grant install, develop on application package {self.package_name} to role {self.app_role}"
299
- )
300
- self._execute_query(
301
- f"grant usage on schema {self.package_name}.{self.stage_schema} to role {self.app_role}"
302
- )
303
- self._execute_query(
304
- f"grant read on stage {self.stage_fqn} to role {self.app_role}"
305
- )
306
-
307
- try:
308
- # by default, applications are created in debug mode when possible;
309
- # this can be overridden in the project definition
310
- debug_mode_clause = ""
311
- if install_method.is_dev_mode:
312
- initial_debug_mode = (
313
- self.debug_mode if self.debug_mode is not None else True
314
- )
315
- debug_mode_clause = f"debug_mode = {initial_debug_mode}"
316
-
317
- using_clause = install_method.using_clause(self._na_project)
318
- create_cursor = self._execute_query(
319
- dedent(
320
- f"""\
321
- create application {self.app_name}
322
- from application package {self.package_name} {using_clause} {debug_mode_clause}
323
- comment = {SPECIAL_COMMENT}
324
- """
325
- ),
326
- )
327
- print_messages(create_cursor)
328
-
329
- # hooks always executed after a create or upgrade
330
- self.execute_app_post_deploy_hooks()
331
-
332
- except ProgrammingError as err:
333
- generic_sql_error_handler(err)
334
-
335
- def process(
336
- self,
337
- bundle_map: BundleMap,
338
- policy: PolicyBase,
339
- version: Optional[str] = None,
340
- patch: Optional[int] = None,
341
- from_release_directive: bool = False,
342
- is_interactive: bool = False,
343
- validate: bool = True,
344
- *args,
345
- **kwargs,
346
- ):
347
- """
348
- Create or upgrade the application object using the given strategy
349
- (unversioned dev, versioned dev, or same-account release directive).
350
- """
351
-
352
- # same-account release directive
353
- if from_release_directive:
354
- self.create_or_upgrade_app(
355
- policy=policy,
356
- is_interactive=is_interactive,
357
- install_method=SameAccountInstallMethod.release_directive(),
358
- )
359
- return
360
-
361
- # versioned dev
362
- if version:
363
- try:
364
- version_exists = self.get_existing_version_info(version)
365
- if not version_exists:
366
- raise UsageError(
367
- 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."
368
- )
369
- except ApplicationPackageDoesNotExistError as app_err:
370
- raise UsageError(
371
- 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."
372
- )
373
-
374
- self.create_or_upgrade_app(
375
- policy=policy,
376
- install_method=SameAccountInstallMethod.versioned_dev(version, patch),
377
- is_interactive=is_interactive,
378
- )
379
- return
380
-
381
- # unversioned dev
382
- self.deploy(
383
- bundle_map=bundle_map, prune=True, recursive=True, validate=validate
384
- )
385
- self.create_or_upgrade_app(
386
- policy=policy,
387
- is_interactive=is_interactive,
388
- install_method=SameAccountInstallMethod.unversioned_dev(),
389
- )
@@ -1,301 +0,0 @@
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
- from pathlib import Path
18
- from textwrap import dedent
19
- from typing import Dict, Optional
20
-
21
- import typer
22
- from snowflake.cli.api.console import cli_console as cc
23
- from snowflake.cli.api.errno import APPLICATION_NO_LONGER_AVAILABLE
24
- from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
25
- from snowflake.cli.plugins.nativeapp.constants import (
26
- ALLOWED_SPECIAL_COMMENTS,
27
- COMMENT_COL,
28
- EXTERNAL_DISTRIBUTION,
29
- INTERNAL_DISTRIBUTION,
30
- OWNER_COL,
31
- )
32
- from snowflake.cli.plugins.nativeapp.exceptions import (
33
- CouldNotDropApplicationPackageWithVersions,
34
- )
35
- from snowflake.cli.plugins.nativeapp.manager import (
36
- NativeAppCommandProcessor,
37
- NativeAppManager,
38
- ensure_correct_owner,
39
- )
40
- from snowflake.cli.plugins.nativeapp.utils import (
41
- needs_confirmation,
42
- )
43
- from snowflake.connector import ProgrammingError
44
- from snowflake.connector.cursor import DictCursor
45
-
46
-
47
- class NativeAppTeardownProcessor(NativeAppManager, NativeAppCommandProcessor):
48
- def __init__(self, project_definition: Dict, project_root: Path):
49
- super().__init__(project_definition, project_root)
50
-
51
- def drop_generic_object(
52
- self, object_type: str, object_name: str, role: str, cascade: bool = False
53
- ):
54
- """
55
- Drop object using the given role.
56
- """
57
- with self.use_role(role):
58
- cc.step(f"Dropping {object_type} {object_name} now.")
59
- drop_query = f"drop {object_type} {object_name}"
60
- if cascade:
61
- drop_query += " cascade"
62
- try:
63
- self._execute_query(drop_query)
64
- except:
65
- raise SnowflakeSQLExecutionError(drop_query)
66
-
67
- cc.message(f"Dropped {object_type} {object_name} successfully.")
68
-
69
- def drop_application(
70
- self, auto_yes: bool, interactive: bool = False, cascade: Optional[bool] = None
71
- ):
72
- """
73
- Attempts to drop the application object if all validations and user prompts allow so.
74
- """
75
-
76
- needs_confirm = True
77
-
78
- # 1. If existing application is not found, exit gracefully
79
- show_obj_row = self.get_existing_app_info()
80
- if show_obj_row is None:
81
- cc.warning(
82
- f"Role {self.app_role} does not own any application object with the name {self.app_name}, or the application object does not exist."
83
- )
84
- return
85
-
86
- # 2. Check for the right owner
87
- ensure_correct_owner(
88
- row=show_obj_row, role=self.app_role, obj_name=self.app_name
89
- )
90
-
91
- # 3. Check if created by the Snowflake CLI
92
- row_comment = show_obj_row[COMMENT_COL]
93
- if row_comment not in ALLOWED_SPECIAL_COMMENTS and needs_confirmation(
94
- needs_confirm, auto_yes
95
- ):
96
- should_drop_object = typer.confirm(
97
- dedent(
98
- f"""\
99
- Application object {self.app_name} was not created by Snowflake CLI.
100
- Application object details:
101
- Name: {self.app_name}
102
- Created on: {show_obj_row["created_on"]}
103
- Source: {show_obj_row["source"]}
104
- Owner: {show_obj_row[OWNER_COL]}
105
- Comment: {show_obj_row[COMMENT_COL]}
106
- Version: {show_obj_row["version"]}
107
- Patch: {show_obj_row["patch"]}
108
- Are you sure you want to drop it?
109
- """
110
- )
111
- )
112
- if not should_drop_object:
113
- cc.message(f"Did not drop application object {self.app_name}.")
114
- # The user desires to keep the app, therefore we can't proceed since it would
115
- # leave behind an orphan app when we get to dropping the package
116
- raise typer.Abort()
117
-
118
- # 4. Check for application objects owned by the application
119
- # This query will fail if the application package has already been dropped, so handle this case gracefully
120
- has_objects_to_drop = False
121
- message_prefix = ""
122
- cascade_true_message = ""
123
- cascade_false_message = ""
124
- interactive_prompt = ""
125
- non_interactive_abort = ""
126
- try:
127
- if application_objects := self.get_objects_owned_by_application():
128
- has_objects_to_drop = True
129
- message_prefix = (
130
- f"The following objects are owned by application {self.app_name}"
131
- )
132
- cascade_true_message = f"{message_prefix} and will be dropped:"
133
- cascade_false_message = f"{message_prefix} and will NOT be dropped:"
134
- interactive_prompt = "Would you like to drop these objects in addition to the application? [y/n/ABORT]"
135
- non_interactive_abort = "Re-run teardown again with --cascade or --no-cascade to specify whether these objects should be dropped along with the application"
136
- except ProgrammingError as e:
137
- if e.errno != APPLICATION_NO_LONGER_AVAILABLE:
138
- raise
139
- application_objects = []
140
- message_prefix = f"Could not determine which objects are owned by application {self.app_name}"
141
- has_objects_to_drop = True # potentially, but we don't know what they are
142
- cascade_true_message = (
143
- f"{message_prefix}, an unknown number of objects will be dropped."
144
- )
145
- cascade_false_message = f"{message_prefix}, they will NOT be dropped."
146
- interactive_prompt = f"Would you like to drop an unknown set of objects in addition to the application? [y/n/ABORT]"
147
- non_interactive_abort = f"Re-run teardown again with --cascade or --no-cascade to specify whether any objects should be dropped along with the application."
148
-
149
- if has_objects_to_drop:
150
- if cascade is True:
151
- # If the user explicitly passed the --cascade flag
152
- cc.message(cascade_true_message)
153
- with cc.indented():
154
- for obj in application_objects:
155
- cc.message(self._application_object_to_str(obj))
156
- elif cascade is False:
157
- # If the user explicitly passed the --no-cascade flag
158
- cc.message(cascade_false_message)
159
- with cc.indented():
160
- for obj in application_objects:
161
- cc.message(self._application_object_to_str(obj))
162
- elif interactive:
163
- # If the user didn't pass any cascade flag and the session is interactive
164
- cc.message(message_prefix)
165
- with cc.indented():
166
- for obj in application_objects:
167
- cc.message(self._application_object_to_str(obj))
168
- user_response = typer.prompt(
169
- interactive_prompt,
170
- show_default=False,
171
- default="ABORT",
172
- ).lower()
173
- if user_response in ["y", "yes"]:
174
- cascade = True
175
- elif user_response in ["n", "no"]:
176
- cascade = False
177
- else:
178
- raise typer.Abort()
179
- else:
180
- # Else abort since we don't know what to do and can't ask the user
181
- cc.message(message_prefix)
182
- with cc.indented():
183
- for obj in application_objects:
184
- cc.message(self._application_object_to_str(obj))
185
- cc.message(non_interactive_abort)
186
- raise typer.Abort()
187
- elif cascade is None:
188
- # If there's nothing to drop, set cascade to an explicit False value
189
- cascade = False
190
-
191
- # 5. All validations have passed, drop object
192
- self.drop_generic_object(
193
- object_type="application",
194
- object_name=self.app_name,
195
- role=self.app_role,
196
- cascade=cascade,
197
- )
198
- return # The application object was successfully dropped, therefore exit gracefully
199
-
200
- def drop_package(self, auto_yes: bool):
201
- """
202
- Attempts to drop application package unless user specifies otherwise.
203
- """
204
- needs_confirm = True
205
-
206
- # 1. If existing application package is not found, exit gracefully
207
- show_obj_row = self.get_existing_app_pkg_info()
208
- if show_obj_row is None:
209
- cc.warning(
210
- f"Role {self.package_role} does not own any application package with the name {self.package_name}, or the application package does not exist."
211
- )
212
- return
213
-
214
- # 2. Check for the right owner
215
- ensure_correct_owner(
216
- row=show_obj_row, role=self.package_role, obj_name=self.package_name
217
- )
218
-
219
- with self.use_role(self.package_role):
220
- # 3. Check for versions in the application package
221
- show_versions_query = (
222
- f"show versions in application package {self.package_name}"
223
- )
224
- show_versions_cursor = self._execute_query(
225
- show_versions_query, cursor_class=DictCursor
226
- )
227
- if show_versions_cursor.rowcount is None:
228
- raise SnowflakeSQLExecutionError(show_versions_query)
229
-
230
- if show_versions_cursor.rowcount > 0:
231
- # allow dropping a package with versions when --force is set
232
- if not auto_yes:
233
- raise CouldNotDropApplicationPackageWithVersions(
234
- "Drop versions first, or use --force to override."
235
- )
236
-
237
- # 4. Check distribution of the existing application package
238
- actual_distribution = self.get_app_pkg_distribution_in_snowflake
239
- if not self.verify_project_distribution(actual_distribution):
240
- cc.warning(
241
- f"Continuing to execute `snow app teardown` on application package {self.package_name} with distribution '{actual_distribution}'."
242
- )
243
-
244
- # 5. If distribution is internal, check if created by the Snowflake CLI
245
- row_comment = show_obj_row[COMMENT_COL]
246
- if actual_distribution == INTERNAL_DISTRIBUTION:
247
- if row_comment in ALLOWED_SPECIAL_COMMENTS:
248
- needs_confirm = False
249
- else:
250
- if needs_confirmation(needs_confirm, auto_yes):
251
- cc.warning(
252
- f"Application package {self.package_name} was not created by Snowflake CLI."
253
- )
254
- else:
255
- if needs_confirmation(needs_confirm, auto_yes):
256
- cc.warning(
257
- f"Application package {self.package_name} in your Snowflake account has distribution property '{EXTERNAL_DISTRIBUTION}' and could be associated with one or more of your listings on Snowflake Marketplace."
258
- )
259
-
260
- if needs_confirmation(needs_confirm, auto_yes):
261
- should_drop_object = typer.confirm(
262
- dedent(
263
- f"""\
264
- Application package details:
265
- Name: {self.app_name}
266
- Created on: {show_obj_row["created_on"]}
267
- Distribution: {actual_distribution}
268
- Owner: {show_obj_row[OWNER_COL]}
269
- Comment: {show_obj_row[COMMENT_COL]}
270
- Are you sure you want to drop it?
271
- """
272
- )
273
- )
274
- if not should_drop_object:
275
- cc.message(f"Did not drop application package {self.package_name}.")
276
- return # The user desires to keep the application package, therefore exit gracefully
277
-
278
- # All validations have passed, drop object
279
- self.drop_generic_object(
280
- object_type="application package",
281
- object_name=self.package_name,
282
- role=self.package_role,
283
- )
284
- return # The application package was successfully dropped, therefore exit gracefully
285
-
286
- def process(
287
- self,
288
- interactive: bool,
289
- force_drop: bool = False,
290
- cascade: Optional[bool] = None,
291
- *args,
292
- **kwargs,
293
- ):
294
-
295
- # Drop the application object
296
- self.drop_application(
297
- auto_yes=force_drop, interactive=interactive, cascade=cascade
298
- )
299
-
300
- # Drop the application package
301
- self.drop_package(auto_yes=force_drop)