snowflake-cli-labs 2.8.1__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 +11 -7
  27. snowflake/cli/{plugins → _plugins}/git/manager.py +55 -9
  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 +2 -2
  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 +3 -2
  59. snowflake/cli/{plugins → _plugins}/notebook/manager.py +5 -5
  60. snowflake/cli/{plugins/nativeapp → _plugins/notebook}/plugin_spec.py +1 -1
  61. snowflake/cli/{plugins → _plugins}/object/command_aliases.py +4 -4
  62. snowflake/cli/{plugins → _plugins}/object/commands.py +4 -5
  63. snowflake/cli/{plugins → _plugins}/object/manager.py +36 -15
  64. snowflake/cli/{plugins → _plugins}/object/plugin_spec.py +1 -1
  65. snowflake/cli/_plugins/snowpark/commands.py +450 -0
  66. snowflake/cli/_plugins/snowpark/common.py +268 -0
  67. snowflake/cli/{plugins → _plugins}/snowpark/models.py +0 -7
  68. snowflake/cli/{plugins → _plugins}/snowpark/package/anaconda_packages.py +2 -36
  69. snowflake/cli/{plugins → _plugins}/snowpark/package/commands.py +13 -74
  70. snowflake/cli/{plugins → _plugins}/snowpark/package/manager.py +2 -2
  71. snowflake/cli/{plugins → _plugins}/snowpark/package_utils.py +5 -5
  72. snowflake/cli/_plugins/snowpark/plugin_spec.py +30 -0
  73. snowflake/cli/_plugins/snowpark/snowpark_entity.py +29 -0
  74. snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +173 -0
  75. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +109 -0
  76. snowflake/cli/{plugins → _plugins}/snowpark/snowpark_shared.py +0 -36
  77. snowflake/cli/{plugins → _plugins}/snowpark/zipper.py +16 -8
  78. snowflake/cli/{plugins → _plugins}/spcs/__init__.py +5 -7
  79. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/commands.py +8 -8
  80. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/manager.py +3 -3
  81. snowflake/cli/{plugins → _plugins}/spcs/image_registry/commands.py +3 -3
  82. snowflake/cli/{plugins → _plugins}/spcs/image_repository/commands.py +6 -6
  83. snowflake/cli/{plugins → _plugins}/spcs/image_repository/manager.py +1 -1
  84. snowflake/cli/{plugins → _plugins}/spcs/plugin_spec.py +1 -1
  85. snowflake/cli/{plugins → _plugins}/spcs/services/commands.py +44 -11
  86. snowflake/cli/{plugins → _plugins}/spcs/services/manager.py +43 -5
  87. snowflake/cli/{plugins → _plugins}/sql/commands.py +20 -17
  88. snowflake/cli/{plugins → _plugins}/sql/manager.py +1 -1
  89. snowflake/cli/{plugins → _plugins}/sql/plugin_spec.py +1 -1
  90. snowflake/cli/{plugins → _plugins}/stage/commands.py +15 -14
  91. snowflake/cli/{plugins → _plugins}/stage/diff.py +1 -47
  92. snowflake/cli/{plugins → _plugins}/stage/manager.py +12 -7
  93. snowflake/cli/{plugins → _plugins}/stage/plugin_spec.py +1 -1
  94. snowflake/cli/_plugins/stage/utils.py +54 -0
  95. snowflake/cli/{plugins → _plugins}/streamlit/commands.py +64 -48
  96. snowflake/cli/{plugins → _plugins}/streamlit/manager.py +67 -69
  97. snowflake/cli/_plugins/streamlit/plugin_spec.py +30 -0
  98. snowflake/cli/_plugins/streamlit/streamlit_entity.py +12 -0
  99. snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +66 -0
  100. snowflake/cli/_plugins/workspace/action_context.py +18 -0
  101. snowflake/cli/_plugins/workspace/commands.py +306 -0
  102. snowflake/cli/_plugins/workspace/manager.py +74 -0
  103. snowflake/cli/_plugins/workspace/plugin_spec.py +30 -0
  104. snowflake/cli/api/cli_global_context.py +152 -295
  105. snowflake/cli/api/commands/common.py +25 -0
  106. snowflake/cli/api/commands/decorators.py +19 -4
  107. snowflake/cli/api/commands/experimental_behaviour.py +2 -3
  108. snowflake/cli/api/commands/flags.py +127 -228
  109. snowflake/cli/api/commands/overrideable_parameter.py +143 -0
  110. snowflake/cli/api/commands/snow_typer.py +21 -11
  111. snowflake/cli/api/commands/utils.py +18 -0
  112. snowflake/cli/api/config.py +44 -12
  113. snowflake/cli/api/connections.py +216 -0
  114. snowflake/cli/api/console/abc.py +8 -3
  115. snowflake/cli/api/constants.py +11 -0
  116. snowflake/cli/api/entities/common.py +56 -0
  117. snowflake/cli/api/entities/utils.py +370 -0
  118. snowflake/cli/api/errno.py +1 -0
  119. snowflake/cli/api/exceptions.py +31 -5
  120. snowflake/cli/api/feature_flags.py +0 -1
  121. snowflake/cli/api/identifiers.py +28 -5
  122. snowflake/cli/api/metrics.py +92 -0
  123. snowflake/cli/api/project/definition.py +48 -6
  124. snowflake/cli/api/project/definition_conversion.py +400 -0
  125. snowflake/cli/api/project/definition_manager.py +16 -5
  126. snowflake/cli/api/project/project_verification.py +3 -3
  127. snowflake/cli/api/project/schemas/entities/common.py +91 -16
  128. snowflake/cli/api/project/schemas/entities/entities.py +37 -6
  129. snowflake/cli/api/project/schemas/project_definition.py +180 -49
  130. snowflake/cli/api/project/schemas/updatable_model.py +11 -3
  131. snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
  132. snowflake/cli/api/project/schemas/{identifier_model.py → v1/identifier_model.py} +3 -1
  133. snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
  134. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/application.py +8 -9
  135. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/native_app.py +4 -4
  136. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/package.py +7 -1
  137. snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
  138. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/callable.py +2 -2
  139. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/snowpark.py +2 -2
  140. snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
  141. snowflake/cli/api/project/schemas/{streamlit → v1/streamlit}/streamlit.py +2 -1
  142. snowflake/cli/api/project/util.py +23 -6
  143. snowflake/cli/api/rendering/jinja.py +14 -8
  144. snowflake/cli/api/rendering/project_definition_templates.py +5 -1
  145. snowflake/cli/api/rendering/sql_templates.py +56 -11
  146. snowflake/cli/api/rest_api.py +11 -5
  147. snowflake/cli/api/secure_path.py +16 -18
  148. snowflake/cli/api/secure_utils.py +90 -1
  149. snowflake/cli/api/sql_execution.py +43 -23
  150. snowflake/cli/api/utils/definition_rendering.py +45 -13
  151. {snowflake_cli_labs-2.8.1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/METADATA +20 -18
  152. snowflake_cli_labs-3.0.0.dist-info/RECORD +242 -0
  153. snowflake_cli_labs-3.0.0.dist-info/entry_points.txt +2 -0
  154. snowflake/cli/api/commands/project_initialisation.py +0 -65
  155. snowflake/cli/api/commands/typer_pre_execute.py +0 -26
  156. snowflake/cli/api/project/schemas/entities/application_entity.py +0 -44
  157. snowflake/cli/api/project/schemas/entities/application_package_entity.py +0 -66
  158. snowflake/cli/app/build_and_push.sh +0 -8
  159. snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -172
  160. snowflake/cli/plugins/nativeapp/init.py +0 -345
  161. snowflake/cli/plugins/nativeapp/manager.py +0 -823
  162. snowflake/cli/plugins/nativeapp/run_processor.py +0 -389
  163. snowflake/cli/plugins/nativeapp/teardown_processor.py +0 -301
  164. snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +0 -135
  165. snowflake/cli/plugins/nativeapp/version/version_processor.py +0 -362
  166. snowflake/cli/plugins/object_stage_deprecated/__init__.py +0 -15
  167. snowflake/cli/plugins/object_stage_deprecated/commands.py +0 -122
  168. snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +0 -32
  169. snowflake/cli/plugins/snowpark/commands.py +0 -546
  170. snowflake/cli/plugins/snowpark/common.py +0 -307
  171. snowflake/cli/plugins/snowpark/manager.py +0 -109
  172. snowflake/cli/plugins/snowpark/plugin_spec.py +0 -30
  173. snowflake/cli/plugins/snowpark/snowpark_package_paths.py +0 -65
  174. snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
  175. snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
  176. snowflake/cli/plugins/streamlit/__init__.py +0 -13
  177. snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
  178. snowflake/cli/plugins/workspace/__init__.py +0 -13
  179. snowflake/cli/plugins/workspace/commands.py +0 -35
  180. snowflake/cli/plugins/workspace/plugin_spec.py +0 -30
  181. snowflake/cli/templates/default_snowpark/.gitignore +0 -4
  182. snowflake/cli/templates/default_snowpark/app/common.py +0 -2
  183. snowflake/cli/templates/default_snowpark/app/functions.py +0 -15
  184. snowflake/cli/templates/default_snowpark/app/procedures.py +0 -22
  185. snowflake/cli/templates/default_snowpark/requirements.txt +0 -1
  186. snowflake/cli/templates/default_snowpark/snowflake.yml +0 -23
  187. snowflake/cli/templates/default_streamlit/.gitignore +0 -4
  188. snowflake/cli/templates/default_streamlit/common/hello.py +0 -2
  189. snowflake/cli/templates/default_streamlit/environment.yml +0 -6
  190. snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -3
  191. snowflake/cli/templates/default_streamlit/snowflake.yml +0 -10
  192. snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -4
  193. snowflake_cli_labs-2.8.1.dist-info/RECORD +0 -240
  194. snowflake_cli_labs-2.8.1.dist-info/entry_points.txt +0 -2
  195. /snowflake/cli/{app → _app}/__init__.py +0 -0
  196. /snowflake/cli/{api/project/schemas/native_app → _app/api_impl}/__init__.py +0 -0
  197. /snowflake/cli/{api/project/schemas/snowpark → _app/api_impl/plugin}/__init__.py +0 -0
  198. /snowflake/cli/{app → _app}/api_impl/plugin/plugin_config_provider_impl.py +0 -0
  199. /snowflake/cli/{app → _app}/commands_registration/__init__.py +0 -0
  200. /snowflake/cli/{app → _app}/commands_registration/threadsafe.py +0 -0
  201. /snowflake/cli/{app → _app}/constants.py +0 -0
  202. /snowflake/cli/{api/project/schemas/streamlit → _app/dev}/__init__.py +0 -0
  203. /snowflake/cli/{app → _app}/dev/commands_structure.py +0 -0
  204. /snowflake/cli/{app/api_impl → _app/dev/docs}/__init__.py +0 -0
  205. /snowflake/cli/{app → _app}/dev/docs/project_definition_generate_json_schema.py +0 -0
  206. /snowflake/cli/{app → _app}/dev/docs/template_utils.py +0 -0
  207. /snowflake/cli/{app → _app}/dev/docs/templates/definition_description.rst.jinja2 +0 -0
  208. /snowflake/cli/{app → _app}/dev/docs/templates/overview.rst.jinja2 +0 -0
  209. /snowflake/cli/{app → _app}/dev/pycharm_remote_debug.py +0 -0
  210. /snowflake/cli/{app → _app}/loggers.py +0 -0
  211. /snowflake/cli/{app/api_impl/plugin → _plugins}/__init__.py +0 -0
  212. /snowflake/cli/{app/dev → _plugins/connection}/__init__.py +0 -0
  213. /snowflake/cli/{app/dev/docs → _plugins/cortex}/__init__.py +0 -0
  214. /snowflake/cli/{plugins → _plugins}/cortex/types.py +0 -0
  215. /snowflake/cli/{plugins → _plugins/git}/__init__.py +0 -0
  216. /snowflake/cli/{plugins/connection → _plugins/helpers}/__init__.py +0 -0
  217. /snowflake/cli/{plugins/cortex → _plugins/init}/__init__.py +0 -0
  218. /snowflake/cli/{plugins/git → _plugins/nativeapp}/__init__.py +0 -0
  219. /snowflake/cli/{plugins/init → _plugins/nativeapp/codegen}/__init__.py +0 -0
  220. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/sandbox.py +0 -0
  221. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -0
  222. /snowflake/cli/{plugins → _plugins}/nativeapp/constants.py +0 -0
  223. /snowflake/cli/{templates/default_snowpark/app → _plugins/nativeapp/entities}/__init__.py +0 -0
  224. /snowflake/cli/{plugins → _plugins}/nativeapp/feature_flags.py +0 -0
  225. /snowflake/cli/{plugins → _plugins}/nativeapp/utils.py +0 -0
  226. /snowflake/cli/{plugins/nativeapp → _plugins/nativeapp/version}/__init__.py +0 -0
  227. /snowflake/cli/{plugins/nativeapp/codegen → _plugins/notebook}/__init__.py +0 -0
  228. /snowflake/cli/{plugins → _plugins}/notebook/exceptions.py +0 -0
  229. /snowflake/cli/{plugins → _plugins}/notebook/types.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.1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/WHEEL +0 -0
  251. {snowflake_cli_labs-2.8.1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,249 @@
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 json
18
+ import logging
19
+ import os.path
20
+ from pathlib import Path
21
+ from typing import List, Optional
22
+
23
+ import yaml
24
+ from click import ClickException
25
+ from snowflake.cli._plugins.nativeapp.artifacts import (
26
+ BundleMap,
27
+ find_manifest_file,
28
+ find_setup_script_file,
29
+ )
30
+ from snowflake.cli._plugins.nativeapp.codegen.artifact_processor import (
31
+ ArtifactProcessor,
32
+ is_python_file_artifact,
33
+ )
34
+ from snowflake.cli._plugins.nativeapp.codegen.sandbox import (
35
+ ExecutionEnvironmentType,
36
+ SandboxEnvBuilder,
37
+ execute_script_in_sandbox,
38
+ )
39
+ from snowflake.cli._plugins.stage.diff import to_stage_path
40
+ from snowflake.cli.api.console import cli_console as cc
41
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import (
42
+ PathMapping,
43
+ ProcessorMapping,
44
+ )
45
+
46
+ DEFAULT_TIMEOUT = 30
47
+ DRIVER_PATH = Path(__file__).parent / "setup_driver.py.source"
48
+
49
+ log = logging.getLogger(__name__)
50
+
51
+
52
+ def safe_set(d: dict, *keys: str, **kwargs) -> None:
53
+ """
54
+ Sets a value in a nested dictionary structure, creating intermediate dictionaries as needed.
55
+ Sample usage:
56
+
57
+ d = {}
58
+ safe_set(d, "a", "b", "c", value=42)
59
+
60
+ d is now:
61
+ {
62
+ "a": {
63
+ "b": {
64
+ "c": 42
65
+ }
66
+ }
67
+ }
68
+ """
69
+ curr = d
70
+ for k in keys[:-1]:
71
+ curr = curr.setdefault(k, {})
72
+
73
+ curr[keys[-1]] = kwargs.get("value")
74
+
75
+
76
+ class NativeAppSetupProcessor(ArtifactProcessor):
77
+ def __init__(self, *args, **kwargs):
78
+ super().__init__(*args, **kwargs)
79
+
80
+ def process(
81
+ self,
82
+ artifact_to_process: PathMapping,
83
+ processor_mapping: Optional[ProcessorMapping],
84
+ **kwargs,
85
+ ) -> None:
86
+ """
87
+ Processes a Python setup script and generates the corresponding SQL commands.
88
+ """
89
+ bundle_map = BundleMap(
90
+ project_root=self._bundle_ctx.project_root,
91
+ deploy_root=self._bundle_ctx.deploy_root,
92
+ )
93
+ bundle_map.add(artifact_to_process)
94
+
95
+ self._create_or_update_sandbox()
96
+
97
+ cc.step("Processing Python setup files")
98
+
99
+ files_to_process = []
100
+ for src_file, dest_file in bundle_map.all_mappings(
101
+ absolute=True, expand_directories=True, predicate=is_python_file_artifact
102
+ ):
103
+ cc.message(
104
+ f"Found Python setup file: {src_file.relative_to(self._bundle_ctx.project_root)}"
105
+ )
106
+ files_to_process.append(src_file)
107
+
108
+ result = self._execute_in_sandbox(files_to_process)
109
+ if not result:
110
+ return # nothing to do
111
+
112
+ logs = result.get("logs", [])
113
+ for msg in logs:
114
+ log.debug(msg)
115
+
116
+ warnings = result.get("warnings", [])
117
+ for msg in warnings:
118
+ cc.warning(msg)
119
+
120
+ schema_version = result.get("schema_version")
121
+ if schema_version != "1":
122
+ raise ClickException(
123
+ f"Unsupported schema version returned from snowflake-app-python library: {schema_version}"
124
+ )
125
+
126
+ setup_script_mods = [
127
+ mod
128
+ for mod in result.get("modifications", [])
129
+ if mod.get("target") == "native_app:setup_script"
130
+ ]
131
+ if setup_script_mods:
132
+ self._edit_setup_sql(setup_script_mods)
133
+
134
+ manifest_mods = [
135
+ mod
136
+ for mod in result.get("modifications", [])
137
+ if mod.get("target") == "native_app:manifest"
138
+ ]
139
+ if manifest_mods:
140
+ self._edit_manifest(manifest_mods)
141
+
142
+ def _execute_in_sandbox(self, py_files: List[Path]) -> dict:
143
+ file_count = len(py_files)
144
+ cc.step(f"Processing {file_count} setup file{'s' if file_count > 1 else ''}")
145
+
146
+ manifest_path = find_manifest_file(deploy_root=self._bundle_ctx.deploy_root)
147
+
148
+ generated_root = self._bundle_ctx.generated_root
149
+ generated_root.mkdir(exist_ok=True, parents=True)
150
+
151
+ env_vars = {
152
+ "_SNOWFLAKE_CLI_PROJECT_PATH": str(self._bundle_ctx.project_root),
153
+ "_SNOWFLAKE_CLI_SETUP_FILES": os.pathsep.join(map(str, py_files)),
154
+ "_SNOWFLAKE_CLI_APP_NAME": str(self._bundle_ctx.package_name),
155
+ "_SNOWFLAKE_CLI_SQL_DEST_DIR": str(generated_root),
156
+ "_SNOWFLAKE_CLI_MANIFEST_PATH": str(manifest_path),
157
+ }
158
+
159
+ try:
160
+ result = execute_script_in_sandbox(
161
+ script_source=DRIVER_PATH.read_text(),
162
+ env_type=ExecutionEnvironmentType.VENV,
163
+ cwd=self._bundle_ctx.bundle_root,
164
+ timeout=DEFAULT_TIMEOUT,
165
+ path=self.sandbox_root,
166
+ env_vars=env_vars,
167
+ )
168
+ except Exception as e:
169
+ raise ClickException(
170
+ f"Exception while executing python setup script logic: {e}"
171
+ )
172
+
173
+ if result.returncode == 0:
174
+ return json.loads(result.stdout)
175
+ else:
176
+ raise ClickException(
177
+ f"Failed to execute python setup script logic: {result.stderr}"
178
+ )
179
+
180
+ def _edit_setup_sql(self, modifications: List[dict]) -> None:
181
+ cc.step("Patching setup script")
182
+ setup_file_path = find_setup_script_file(
183
+ deploy_root=self._bundle_ctx.deploy_root
184
+ )
185
+
186
+ with self.edit_file(setup_file_path) as f:
187
+ prepended = []
188
+ appended = []
189
+
190
+ for mod in modifications:
191
+ for inst in mod.get("instructions", []):
192
+ if inst.get("type") == "insert":
193
+ default_loc = inst.get("default_location")
194
+ if default_loc == "end":
195
+ appended.append(self._setup_mod_instruction_to_sql(inst))
196
+ elif default_loc == "start":
197
+ prepended.append(self._setup_mod_instruction_to_sql(inst))
198
+
199
+ if prepended or appended:
200
+ f.edited_contents = "\n".join(prepended + [f.contents] + appended)
201
+
202
+ def _edit_manifest(self, modifications: List[dict]) -> None:
203
+ cc.step("Patching manifest")
204
+ manifest_path = find_manifest_file(deploy_root=self._bundle_ctx.deploy_root)
205
+
206
+ with self.edit_file(manifest_path) as f:
207
+ manifest = yaml.safe_load(f.contents)
208
+
209
+ for mod in modifications:
210
+ for inst in mod.get("instructions", []):
211
+ if inst.get("type") == "set":
212
+ payload = inst.get("payload")
213
+ if payload:
214
+ key = payload.get("key")
215
+ value = payload.get("value")
216
+ safe_set(manifest, *key.split("."), value=value)
217
+ f.edited_contents = yaml.safe_dump(manifest, sort_keys=False)
218
+
219
+ def _setup_mod_instruction_to_sql(self, mod_inst: dict) -> str:
220
+ payload = mod_inst.get("payload")
221
+ if not payload:
222
+ raise ClickException("Unsupported instruction received: no payload found")
223
+
224
+ payload_type = payload.get("type")
225
+ if payload_type == "execute immediate":
226
+ file_path = payload.get("file_path")
227
+ if file_path:
228
+ sql_file_path = self._bundle_ctx.generated_root / file_path
229
+ return f"EXECUTE IMMEDIATE FROM '/{to_stage_path(sql_file_path.relative_to(self._bundle_ctx.deploy_root))}';"
230
+
231
+ raise ClickException(f"Unsupported instruction type received: {payload_type}")
232
+
233
+ @property
234
+ def sandbox_root(self):
235
+ return self._bundle_ctx.bundle_root / "venv"
236
+
237
+ def _create_or_update_sandbox(self):
238
+ sandbox_root = self.sandbox_root
239
+ env_builder = SandboxEnvBuilder(sandbox_root, with_pip=True)
240
+ if sandbox_root.exists():
241
+ cc.step("Virtual environment found")
242
+ else:
243
+ cc.step(
244
+ f"Creating virtual environment in {sandbox_root.relative_to(self._bundle_ctx.project_root)}"
245
+ )
246
+ env_builder.ensure_created()
247
+
248
+ # Temporarily fetch the library from a location specified via env vars
249
+ env_builder.pip_install(os.environ["SNOWFLAKE_APP_PYTHON_LOC"])
@@ -20,8 +20,11 @@ from pathlib import Path
20
20
  import snowflake.app.context as ctx
21
21
  from snowflake.app.sql import SQLGenerator
22
22
 
23
- ctx._project_path = os.environ["_SNOWFLAKE_CLI_PROJECT_PATH"]
24
- ctx._current_app_name = os.environ["_SNOWFLAKE_CLI_APP_NAME"]
23
+ ctx.configure("project_path", os.environ.get("_SNOWFLAKE_CLI_PROJECT_PATH", None))
24
+ ctx.configure("manifest_path", os.environ.get("_SNOWFLAKE_CLI_MANIFEST_PATH", None))
25
+ ctx.configure("current_app_name", os.environ.get("_SNOWFLAKE_CLI_APP_NAME", None))
26
+ ctx.configure("enable_sql_generation", True)
27
+
25
28
  __snowflake_internal_py_files = os.environ["_SNOWFLAKE_CLI_SETUP_FILES"].split(
26
29
  os.pathsep
27
30
  )
@@ -23,17 +23,17 @@ from typing import (
23
23
  )
24
24
 
25
25
  from click.exceptions import ClickException
26
- from snowflake.cli.api.project.schemas.snowpark.argument import Argument
26
+ from snowflake.cli._plugins.nativeapp.codegen.snowpark.models import (
27
+ ExtensionFunctionTypeEnum,
28
+ NativeAppExtensionFunction,
29
+ )
30
+ from snowflake.cli.api.project.schemas.v1.snowpark.argument import Argument
27
31
  from snowflake.cli.api.project.util import (
28
32
  is_valid_identifier,
29
33
  is_valid_string_literal,
30
34
  to_identifier,
31
35
  to_string_literal,
32
36
  )
33
- from snowflake.cli.plugins.nativeapp.codegen.snowpark.models import (
34
- ExtensionFunctionTypeEnum,
35
- NativeAppExtensionFunction,
36
- )
37
37
 
38
38
  ASTDefNode = Union[ast.FunctionDef, ast.ClassDef]
39
39
 
@@ -18,8 +18,8 @@ from enum import Enum
18
18
  from typing import List, Optional
19
19
 
20
20
  from pydantic import Field
21
- from snowflake.cli.api.project.schemas.snowpark.callable import _CallableBase
22
21
  from snowflake.cli.api.project.schemas.updatable_model import IdentifierField
22
+ from snowflake.cli.api.project.schemas.v1.snowpark.callable import _CallableBase
23
23
 
24
24
 
25
25
  class ExtensionFunctionTypeEnum(str, Enum):
@@ -21,26 +21,20 @@ from textwrap import dedent
21
21
  from typing import Any, Dict, List, Optional, Set
22
22
 
23
23
  from pydantic import ValidationError
24
- from snowflake.cli.api.console import cli_console as cc
25
- from snowflake.cli.api.project.schemas.native_app.path_mapping import (
26
- PathMapping,
27
- ProcessorMapping,
28
- )
29
- from snowflake.cli.api.rendering.jinja import jinja_render_from_file
30
- from snowflake.cli.plugins.nativeapp.artifacts import (
24
+ from snowflake.cli._plugins.nativeapp.artifacts import (
31
25
  BundleMap,
32
26
  find_setup_script_file,
33
27
  )
34
- from snowflake.cli.plugins.nativeapp.codegen.artifact_processor import (
28
+ from snowflake.cli._plugins.nativeapp.codegen.artifact_processor import (
35
29
  ArtifactProcessor,
36
30
  is_python_file_artifact,
37
31
  )
38
- from snowflake.cli.plugins.nativeapp.codegen.sandbox import (
32
+ from snowflake.cli._plugins.nativeapp.codegen.sandbox import (
39
33
  ExecutionEnvironmentType,
40
34
  SandboxExecutionError,
41
35
  execute_script_in_sandbox,
42
36
  )
43
- from snowflake.cli.plugins.nativeapp.codegen.snowpark.extension_function_utils import (
37
+ from snowflake.cli._plugins.nativeapp.codegen.snowpark.extension_function_utils import (
44
38
  deannotate_module_source,
45
39
  ensure_all_string_literals,
46
40
  ensure_string_literal,
@@ -49,12 +43,19 @@ from snowflake.cli.plugins.nativeapp.codegen.snowpark.extension_function_utils i
49
43
  get_sql_argument_signature,
50
44
  get_sql_object_type,
51
45
  )
52
- from snowflake.cli.plugins.nativeapp.codegen.snowpark.models import (
46
+ from snowflake.cli._plugins.nativeapp.codegen.snowpark.models import (
53
47
  ExtensionFunctionTypeEnum,
54
48
  NativeAppExtensionFunction,
55
49
  )
56
- from snowflake.cli.plugins.nativeapp.project_model import NativeAppProjectModel
57
- from snowflake.cli.plugins.stage.diff import to_stage_path
50
+ from snowflake.cli._plugins.stage.diff import to_stage_path
51
+ from snowflake.cli.api.cli_global_context import get_cli_context
52
+ from snowflake.cli.api.console import cli_console as cc
53
+ from snowflake.cli.api.metrics import CLICounterField
54
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import (
55
+ PathMapping,
56
+ ProcessorMapping,
57
+ )
58
+ from snowflake.cli.api.rendering.jinja import jinja_render_from_file
58
59
 
59
60
  DEFAULT_TIMEOUT = 30
60
61
  TEMPLATE_PATH = Path(__file__).parent / "callback_source.py.jinja"
@@ -163,11 +164,8 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
163
164
  and generate SQL code for creation of extension functions based on those discovered objects.
164
165
  """
165
166
 
166
- def __init__(
167
- self,
168
- na_project: NativeAppProjectModel,
169
- ):
170
- super().__init__(na_project=na_project)
167
+ def __init__(self, *args, **kwargs):
168
+ super().__init__(*args, **kwargs)
171
169
 
172
170
  def process(
173
171
  self,
@@ -180,9 +178,11 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
180
178
  setup script with generated SQL that registers these functions.
181
179
  """
182
180
 
181
+ get_cli_context().metrics.set_counter(CLICounterField.SNOWPARK_PROCESSOR, 1)
182
+
183
183
  bundle_map = BundleMap(
184
- project_root=self._na_project.project_root,
185
- deploy_root=self._na_project.deploy_root,
184
+ project_root=self._bundle_ctx.project_root,
185
+ deploy_root=self._bundle_ctx.deploy_root,
186
186
  )
187
187
  bundle_map.add(artifact_to_process)
188
188
 
@@ -230,13 +230,9 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
230
230
  edit_setup_script_with_exec_imm_sql(
231
231
  collected_sql_files=collected_sql_files,
232
232
  deploy_root=bundle_map.deploy_root(),
233
- generated_root=self._generated_root,
233
+ generated_root=self._bundle_ctx.generated_root,
234
234
  )
235
235
 
236
- @property
237
- def _generated_root(self):
238
- return self._na_project.generated_root / "snowpark"
239
-
240
236
  def _normalize_imports(
241
237
  self,
242
238
  extension_fn: NativeAppExtensionFunction,
@@ -315,7 +311,7 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
315
311
  self, bundle_map: BundleMap, processor_mapping: Optional[ProcessorMapping]
316
312
  ) -> Dict[Path, List[NativeAppExtensionFunction]]:
317
313
  kwargs = (
318
- _determine_virtual_env(self._na_project.project_root, processor_mapping)
314
+ _determine_virtual_env(self._bundle_ctx.project_root, processor_mapping)
319
315
  if processor_mapping is not None
320
316
  else {}
321
317
  )
@@ -331,14 +327,11 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
331
327
  predicate=is_python_file_artifact,
332
328
  )
333
329
  ):
334
- cc.step(
335
- "Processing Snowpark annotations from {}".format(
336
- dest_file.relative_to(bundle_map.deploy_root())
337
- )
338
- )
330
+ src_file_name = src_file.relative_to(self._bundle_ctx.project_root)
331
+ cc.step(f"Processing Snowpark annotations from {src_file_name}")
339
332
  collected_extension_function_json = _execute_in_sandbox(
340
333
  py_file=str(dest_file.resolve()),
341
- deploy_root=self._na_project.deploy_root,
334
+ deploy_root=self._bundle_ctx.deploy_root,
342
335
  kwargs=kwargs,
343
336
  )
344
337
 
@@ -369,8 +362,10 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
369
362
  """
370
363
  Generates a SQL filename for the generated root from the python file, and creates its parent directories.
371
364
  """
372
- relative_py_file = py_file.relative_to(self._na_project.deploy_root)
373
- sql_file = Path(self._generated_root, relative_py_file.with_suffix(".sql"))
365
+ relative_py_file = py_file.relative_to(self._bundle_ctx.deploy_root)
366
+ sql_file = Path(
367
+ self._bundle_ctx.generated_root, relative_py_file.with_suffix(".sql")
368
+ )
374
369
  if sql_file.exists():
375
370
  cc.warning(
376
371
  f"""\
@@ -0,0 +1,114 @@
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 typing import Optional
19
+
20
+ import jinja2
21
+ from snowflake.cli._plugins.nativeapp.artifacts import BundleMap
22
+ from snowflake.cli._plugins.nativeapp.codegen.artifact_processor import (
23
+ ArtifactProcessor,
24
+ )
25
+ from snowflake.cli._plugins.nativeapp.exceptions import InvalidTemplateInFileError
26
+ from snowflake.cli.api.cli_global_context import get_cli_context
27
+ from snowflake.cli.api.console import cli_console as cc
28
+ from snowflake.cli.api.metrics import CLICounterField
29
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import (
30
+ PathMapping,
31
+ ProcessorMapping,
32
+ )
33
+ from snowflake.cli.api.rendering.project_definition_templates import (
34
+ get_client_side_jinja_env,
35
+ has_client_side_templates,
36
+ )
37
+ from snowflake.cli.api.rendering.sql_templates import (
38
+ choose_sql_jinja_env_based_on_template_syntax,
39
+ has_sql_templates,
40
+ )
41
+
42
+
43
+ def _is_sql_file(file: Path) -> bool:
44
+ return file.name.lower().endswith(".sql")
45
+
46
+
47
+ class TemplatesProcessor(ArtifactProcessor):
48
+ """
49
+ Processor class to perform template expansion on all relevant artifacts (specified in the project definition file).
50
+ """
51
+
52
+ def expand_templates_in_file(self, src: Path, dest: Path) -> None:
53
+ """
54
+ Expand templates in the file.
55
+ """
56
+ if src.is_dir():
57
+ return
58
+
59
+ with self.edit_file(dest) as file:
60
+ if not has_client_side_templates(file.contents) and not (
61
+ _is_sql_file(dest) and has_sql_templates(file.contents)
62
+ ):
63
+ return
64
+
65
+ src_file_name = src.relative_to(self._bundle_ctx.project_root)
66
+ cc.step(f"Expanding templates in {src_file_name}")
67
+ with cc.indented():
68
+ try:
69
+ jinja_env = (
70
+ choose_sql_jinja_env_based_on_template_syntax(
71
+ file.contents, reference_name=src_file_name
72
+ )
73
+ if _is_sql_file(dest)
74
+ else get_client_side_jinja_env()
75
+ )
76
+ expanded_template = jinja_env.from_string(file.contents).render(
77
+ get_cli_context().template_context
78
+ )
79
+
80
+ # For now, we are printing the source file path in the error message
81
+ # instead of the destination file path to make it easier for the user
82
+ # to identify the file that has the error, and edit the correct file.
83
+ except jinja2.TemplateSyntaxError as e:
84
+ raise InvalidTemplateInFileError(src_file_name, e, e.lineno) from e
85
+
86
+ except jinja2.UndefinedError as e:
87
+ raise InvalidTemplateInFileError(src_file_name, e) from e
88
+
89
+ if expanded_template != file.contents:
90
+ file.edited_contents = expanded_template
91
+
92
+ def process(
93
+ self,
94
+ artifact_to_process: PathMapping,
95
+ processor_mapping: Optional[ProcessorMapping],
96
+ **kwargs,
97
+ ) -> None:
98
+ """
99
+ Process the artifact by executing the template expansion logic on it.
100
+ """
101
+
102
+ get_cli_context().metrics.set_counter(CLICounterField.TEMPLATES_PROCESSOR, 1)
103
+
104
+ bundle_map = BundleMap(
105
+ project_root=self._bundle_ctx.project_root,
106
+ deploy_root=self._bundle_ctx.deploy_root,
107
+ )
108
+ bundle_map.add(artifact_to_process)
109
+
110
+ for src, dest in bundle_map.all_mappings(
111
+ absolute=True,
112
+ expand_directories=True,
113
+ ):
114
+ self.expand_templates_in_file(src, dest)