snowflake-cli-labs 3.0.0rc5__py3-none-any.whl → 3.0.2__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 (244) hide show
  1. README.md +21 -0
  2. {snowflake_cli_labs-3.0.0rc5.dist-info → snowflake_cli_labs-3.0.2.dist-info}/METADATA +6 -96
  3. snowflake_cli_labs-3.0.2.dist-info/RECORD +5 -0
  4. snowflake/cli/__about__.py +0 -17
  5. snowflake/cli/__init__.py +0 -13
  6. snowflake/cli/_app/__init__.py +0 -22
  7. snowflake/cli/_app/__main__.py +0 -31
  8. snowflake/cli/_app/api_impl/__init__.py +0 -13
  9. snowflake/cli/_app/api_impl/plugin/__init__.py +0 -13
  10. snowflake/cli/_app/api_impl/plugin/plugin_config_provider_impl.py +0 -66
  11. snowflake/cli/_app/cli_app.py +0 -252
  12. snowflake/cli/_app/commands_registration/__init__.py +0 -33
  13. snowflake/cli/_app/commands_registration/builtin_plugins.py +0 -50
  14. snowflake/cli/_app/commands_registration/command_plugins_loader.py +0 -169
  15. snowflake/cli/_app/commands_registration/commands_registration_with_callbacks.py +0 -105
  16. snowflake/cli/_app/commands_registration/exception_logging.py +0 -26
  17. snowflake/cli/_app/commands_registration/threadsafe.py +0 -48
  18. snowflake/cli/_app/commands_registration/typer_registration.py +0 -153
  19. snowflake/cli/_app/constants.py +0 -19
  20. snowflake/cli/_app/dev/__init__.py +0 -13
  21. snowflake/cli/_app/dev/commands_structure.py +0 -48
  22. snowflake/cli/_app/dev/docs/__init__.py +0 -13
  23. snowflake/cli/_app/dev/docs/commands_docs_generator.py +0 -118
  24. snowflake/cli/_app/dev/docs/generator.py +0 -35
  25. snowflake/cli/_app/dev/docs/project_definition_docs_generator.py +0 -58
  26. snowflake/cli/_app/dev/docs/project_definition_generate_json_schema.py +0 -227
  27. snowflake/cli/_app/dev/docs/template_utils.py +0 -23
  28. snowflake/cli/_app/dev/docs/templates/definition_description.rst.jinja2 +0 -38
  29. snowflake/cli/_app/dev/docs/templates/overview.rst.jinja2 +0 -9
  30. snowflake/cli/_app/dev/docs/templates/usage.rst.jinja2 +0 -67
  31. snowflake/cli/_app/dev/pycharm_remote_debug.py +0 -46
  32. snowflake/cli/_app/loggers.py +0 -199
  33. snowflake/cli/_app/main_typer.py +0 -62
  34. snowflake/cli/_app/printing.py +0 -181
  35. snowflake/cli/_app/secret.py +0 -9
  36. snowflake/cli/_app/snow_connector.py +0 -309
  37. snowflake/cli/_app/telemetry.py +0 -220
  38. snowflake/cli/_app/version_check.py +0 -74
  39. snowflake/cli/_plugins/__init__.py +0 -13
  40. snowflake/cli/_plugins/connection/__init__.py +0 -13
  41. snowflake/cli/_plugins/connection/commands.py +0 -353
  42. snowflake/cli/_plugins/connection/plugin_spec.py +0 -30
  43. snowflake/cli/_plugins/connection/util.py +0 -195
  44. snowflake/cli/_plugins/cortex/__init__.py +0 -13
  45. snowflake/cli/_plugins/cortex/commands.py +0 -332
  46. snowflake/cli/_plugins/cortex/constants.py +0 -17
  47. snowflake/cli/_plugins/cortex/manager.py +0 -189
  48. snowflake/cli/_plugins/cortex/plugin_spec.py +0 -30
  49. snowflake/cli/_plugins/cortex/types.py +0 -22
  50. snowflake/cli/_plugins/git/__init__.py +0 -13
  51. snowflake/cli/_plugins/git/commands.py +0 -358
  52. snowflake/cli/_plugins/git/manager.py +0 -151
  53. snowflake/cli/_plugins/git/plugin_spec.py +0 -30
  54. snowflake/cli/_plugins/helpers/__init__.py +0 -13
  55. snowflake/cli/_plugins/helpers/commands.py +0 -90
  56. snowflake/cli/_plugins/helpers/plugin_spec.py +0 -30
  57. snowflake/cli/_plugins/init/__init__.py +0 -13
  58. snowflake/cli/_plugins/init/commands.py +0 -248
  59. snowflake/cli/_plugins/init/plugin_spec.py +0 -30
  60. snowflake/cli/_plugins/nativeapp/__init__.py +0 -13
  61. snowflake/cli/_plugins/nativeapp/artifacts.py +0 -757
  62. snowflake/cli/_plugins/nativeapp/bundle_context.py +0 -31
  63. snowflake/cli/_plugins/nativeapp/codegen/__init__.py +0 -13
  64. snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +0 -91
  65. snowflake/cli/_plugins/nativeapp/codegen/compiler.py +0 -149
  66. snowflake/cli/_plugins/nativeapp/codegen/sandbox.py +0 -306
  67. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -249
  68. snowflake/cli/_plugins/nativeapp/codegen/setup/setup_driver.py.source +0 -59
  69. snowflake/cli/_plugins/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -181
  70. snowflake/cli/_plugins/nativeapp/codegen/snowpark/extension_function_utils.py +0 -217
  71. snowflake/cli/_plugins/nativeapp/codegen/snowpark/models.py +0 -61
  72. snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +0 -523
  73. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +0 -114
  74. snowflake/cli/_plugins/nativeapp/commands.py +0 -559
  75. snowflake/cli/_plugins/nativeapp/common_flags.py +0 -44
  76. snowflake/cli/_plugins/nativeapp/constants.py +0 -27
  77. snowflake/cli/_plugins/nativeapp/entities/__init__.py +0 -0
  78. snowflake/cli/_plugins/nativeapp/entities/application.py +0 -878
  79. snowflake/cli/_plugins/nativeapp/entities/application_package.py +0 -1392
  80. snowflake/cli/_plugins/nativeapp/exceptions.py +0 -113
  81. snowflake/cli/_plugins/nativeapp/feature_flags.py +0 -24
  82. snowflake/cli/_plugins/nativeapp/manager.py +0 -415
  83. snowflake/cli/_plugins/nativeapp/plugin_spec.py +0 -30
  84. snowflake/cli/_plugins/nativeapp/policy.py +0 -53
  85. snowflake/cli/_plugins/nativeapp/project_model.py +0 -211
  86. snowflake/cli/_plugins/nativeapp/run_processor.py +0 -184
  87. snowflake/cli/_plugins/nativeapp/same_account_install_method.py +0 -70
  88. snowflake/cli/_plugins/nativeapp/teardown_processor.py +0 -70
  89. snowflake/cli/_plugins/nativeapp/utils.py +0 -98
  90. snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +0 -262
  91. snowflake/cli/_plugins/nativeapp/version/__init__.py +0 -13
  92. snowflake/cli/_plugins/nativeapp/version/commands.py +0 -141
  93. snowflake/cli/_plugins/nativeapp/version/version_processor.py +0 -98
  94. snowflake/cli/_plugins/notebook/__init__.py +0 -13
  95. snowflake/cli/_plugins/notebook/commands.py +0 -86
  96. snowflake/cli/_plugins/notebook/exceptions.py +0 -20
  97. snowflake/cli/_plugins/notebook/manager.py +0 -71
  98. snowflake/cli/_plugins/notebook/plugin_spec.py +0 -30
  99. snowflake/cli/_plugins/notebook/types.py +0 -15
  100. snowflake/cli/_plugins/object/__init__.py +0 -13
  101. snowflake/cli/_plugins/object/command_aliases.py +0 -95
  102. snowflake/cli/_plugins/object/commands.py +0 -180
  103. snowflake/cli/_plugins/object/common.py +0 -85
  104. snowflake/cli/_plugins/object/manager.py +0 -118
  105. snowflake/cli/_plugins/object/plugin_spec.py +0 -30
  106. snowflake/cli/_plugins/snowpark/__init__.py +0 -13
  107. snowflake/cli/_plugins/snowpark/commands.py +0 -450
  108. snowflake/cli/_plugins/snowpark/common.py +0 -268
  109. snowflake/cli/_plugins/snowpark/models.py +0 -150
  110. snowflake/cli/_plugins/snowpark/package/__init__.py +0 -13
  111. snowflake/cli/_plugins/snowpark/package/anaconda_packages.py +0 -199
  112. snowflake/cli/_plugins/snowpark/package/commands.py +0 -195
  113. snowflake/cli/_plugins/snowpark/package/manager.py +0 -44
  114. snowflake/cli/_plugins/snowpark/package/utils.py +0 -26
  115. snowflake/cli/_plugins/snowpark/package_utils.py +0 -354
  116. snowflake/cli/_plugins/snowpark/plugin_spec.py +0 -30
  117. snowflake/cli/_plugins/snowpark/snowpark_entity.py +0 -29
  118. snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +0 -173
  119. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +0 -109
  120. snowflake/cli/_plugins/snowpark/snowpark_shared.py +0 -59
  121. snowflake/cli/_plugins/snowpark/zipper.py +0 -89
  122. snowflake/cli/_plugins/spcs/__init__.py +0 -33
  123. snowflake/cli/_plugins/spcs/common.py +0 -99
  124. snowflake/cli/_plugins/spcs/compute_pool/__init__.py +0 -13
  125. snowflake/cli/_plugins/spcs/compute_pool/commands.py +0 -241
  126. snowflake/cli/_plugins/spcs/compute_pool/manager.py +0 -121
  127. snowflake/cli/_plugins/spcs/image_registry/__init__.py +0 -13
  128. snowflake/cli/_plugins/spcs/image_registry/commands.py +0 -65
  129. snowflake/cli/_plugins/spcs/image_registry/manager.py +0 -105
  130. snowflake/cli/_plugins/spcs/image_repository/__init__.py +0 -13
  131. snowflake/cli/_plugins/spcs/image_repository/commands.py +0 -202
  132. snowflake/cli/_plugins/spcs/image_repository/manager.py +0 -84
  133. snowflake/cli/_plugins/spcs/plugin_spec.py +0 -30
  134. snowflake/cli/_plugins/spcs/services/__init__.py +0 -13
  135. snowflake/cli/_plugins/spcs/services/commands.py +0 -345
  136. snowflake/cli/_plugins/spcs/services/manager.py +0 -208
  137. snowflake/cli/_plugins/sql/__init__.py +0 -13
  138. snowflake/cli/_plugins/sql/commands.py +0 -86
  139. snowflake/cli/_plugins/sql/manager.py +0 -92
  140. snowflake/cli/_plugins/sql/plugin_spec.py +0 -30
  141. snowflake/cli/_plugins/sql/snowsql_templating.py +0 -28
  142. snowflake/cli/_plugins/stage/__init__.py +0 -13
  143. snowflake/cli/_plugins/stage/commands.py +0 -264
  144. snowflake/cli/_plugins/stage/diff.py +0 -280
  145. snowflake/cli/_plugins/stage/manager.py +0 -582
  146. snowflake/cli/_plugins/stage/md5.py +0 -160
  147. snowflake/cli/_plugins/stage/plugin_spec.py +0 -30
  148. snowflake/cli/_plugins/stage/utils.py +0 -54
  149. snowflake/cli/_plugins/streamlit/__init__.py +0 -13
  150. snowflake/cli/_plugins/streamlit/commands.py +0 -195
  151. snowflake/cli/_plugins/streamlit/manager.py +0 -220
  152. snowflake/cli/_plugins/streamlit/plugin_spec.py +0 -30
  153. snowflake/cli/_plugins/streamlit/streamlit_entity.py +0 -12
  154. snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +0 -66
  155. snowflake/cli/_plugins/workspace/__init__.py +0 -13
  156. snowflake/cli/_plugins/workspace/action_context.py +0 -18
  157. snowflake/cli/_plugins/workspace/commands.py +0 -306
  158. snowflake/cli/_plugins/workspace/manager.py +0 -74
  159. snowflake/cli/_plugins/workspace/plugin_spec.py +0 -30
  160. snowflake/cli/api/__init__.py +0 -48
  161. snowflake/cli/api/cli_global_context.py +0 -247
  162. snowflake/cli/api/commands/__init__.py +0 -13
  163. snowflake/cli/api/commands/alias.py +0 -23
  164. snowflake/cli/api/commands/common.py +0 -25
  165. snowflake/cli/api/commands/decorators.py +0 -369
  166. snowflake/cli/api/commands/execution_metadata.py +0 -40
  167. snowflake/cli/api/commands/experimental_behaviour.py +0 -18
  168. snowflake/cli/api/commands/flags.py +0 -561
  169. snowflake/cli/api/commands/overrideable_parameter.py +0 -143
  170. snowflake/cli/api/commands/snow_typer.py +0 -247
  171. snowflake/cli/api/commands/utils.py +0 -18
  172. snowflake/cli/api/config.py +0 -380
  173. snowflake/cli/api/connections.py +0 -216
  174. snowflake/cli/api/console/__init__.py +0 -17
  175. snowflake/cli/api/console/abc.py +0 -94
  176. snowflake/cli/api/console/console.py +0 -134
  177. snowflake/cli/api/console/enum.py +0 -17
  178. snowflake/cli/api/constants.py +0 -90
  179. snowflake/cli/api/entities/common.py +0 -56
  180. snowflake/cli/api/entities/utils.py +0 -370
  181. snowflake/cli/api/errno.py +0 -28
  182. snowflake/cli/api/exceptions.py +0 -190
  183. snowflake/cli/api/feature_flags.py +0 -54
  184. snowflake/cli/api/identifiers.py +0 -190
  185. snowflake/cli/api/metrics.py +0 -92
  186. snowflake/cli/api/output/__init__.py +0 -13
  187. snowflake/cli/api/output/formats.py +0 -20
  188. snowflake/cli/api/output/types.py +0 -118
  189. snowflake/cli/api/plugins/__init__.py +0 -13
  190. snowflake/cli/api/plugins/command/__init__.py +0 -72
  191. snowflake/cli/api/plugins/command/plugin_hook_specs.py +0 -21
  192. snowflake/cli/api/plugins/plugin_config.py +0 -32
  193. snowflake/cli/api/project/__init__.py +0 -13
  194. snowflake/cli/api/project/definition.py +0 -126
  195. snowflake/cli/api/project/definition_conversion.py +0 -400
  196. snowflake/cli/api/project/definition_manager.py +0 -145
  197. snowflake/cli/api/project/errors.py +0 -56
  198. snowflake/cli/api/project/project_verification.py +0 -23
  199. snowflake/cli/api/project/schemas/__init__.py +0 -13
  200. snowflake/cli/api/project/schemas/entities/__init__.py +0 -13
  201. snowflake/cli/api/project/schemas/entities/common.py +0 -153
  202. snowflake/cli/api/project/schemas/entities/entities.py +0 -61
  203. snowflake/cli/api/project/schemas/project_definition.py +0 -330
  204. snowflake/cli/api/project/schemas/template.py +0 -77
  205. snowflake/cli/api/project/schemas/updatable_model.py +0 -202
  206. snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
  207. snowflake/cli/api/project/schemas/v1/identifier_model.py +0 -51
  208. snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
  209. snowflake/cli/api/project/schemas/v1/native_app/application.py +0 -61
  210. snowflake/cli/api/project/schemas/v1/native_app/native_app.py +0 -93
  211. snowflake/cli/api/project/schemas/v1/native_app/package.py +0 -84
  212. snowflake/cli/api/project/schemas/v1/native_app/path_mapping.py +0 -65
  213. snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
  214. snowflake/cli/api/project/schemas/v1/snowpark/argument.py +0 -28
  215. snowflake/cli/api/project/schemas/v1/snowpark/callable.py +0 -69
  216. snowflake/cli/api/project/schemas/v1/snowpark/snowpark.py +0 -36
  217. snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
  218. snowflake/cli/api/project/schemas/v1/streamlit/streamlit.py +0 -47
  219. snowflake/cli/api/project/util.py +0 -278
  220. snowflake/cli/api/rendering/__init__.py +0 -13
  221. snowflake/cli/api/rendering/jinja.py +0 -118
  222. snowflake/cli/api/rendering/project_definition_templates.py +0 -43
  223. snowflake/cli/api/rendering/project_templates.py +0 -98
  224. snowflake/cli/api/rendering/sql_templates.py +0 -105
  225. snowflake/cli/api/rest_api.py +0 -178
  226. snowflake/cli/api/sanitizers.py +0 -43
  227. snowflake/cli/api/secure_path.py +0 -360
  228. snowflake/cli/api/secure_utils.py +0 -118
  229. snowflake/cli/api/sql_execution.py +0 -280
  230. snowflake/cli/api/utils/__init__.py +0 -13
  231. snowflake/cli/api/utils/cursor.py +0 -34
  232. snowflake/cli/api/utils/definition_rendering.py +0 -415
  233. snowflake/cli/api/utils/dict_utils.py +0 -73
  234. snowflake/cli/api/utils/error_handling.py +0 -23
  235. snowflake/cli/api/utils/graph.py +0 -97
  236. snowflake/cli/api/utils/models.py +0 -63
  237. snowflake/cli/api/utils/naming_utils.py +0 -13
  238. snowflake/cli/api/utils/path_utils.py +0 -36
  239. snowflake/cli/api/utils/templating_functions.py +0 -144
  240. snowflake/cli/api/utils/types.py +0 -35
  241. snowflake_cli_labs-3.0.0rc5.dist-info/RECORD +0 -242
  242. snowflake_cli_labs-3.0.0rc5.dist-info/entry_points.txt +0 -2
  243. {snowflake_cli_labs-3.0.0rc5.dist-info → snowflake_cli_labs-3.0.2.dist-info}/WHEEL +0 -0
  244. {snowflake_cli_labs-3.0.0rc5.dist-info → snowflake_cli_labs-3.0.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,523 +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
- import json
18
- import re
19
- from pathlib import Path
20
- from textwrap import dedent
21
- from typing import Any, Dict, List, Optional, Set
22
-
23
- from pydantic import ValidationError
24
- from snowflake.cli._plugins.nativeapp.artifacts import (
25
- BundleMap,
26
- find_setup_script_file,
27
- )
28
- from snowflake.cli._plugins.nativeapp.codegen.artifact_processor import (
29
- ArtifactProcessor,
30
- is_python_file_artifact,
31
- )
32
- from snowflake.cli._plugins.nativeapp.codegen.sandbox import (
33
- ExecutionEnvironmentType,
34
- SandboxExecutionError,
35
- execute_script_in_sandbox,
36
- )
37
- from snowflake.cli._plugins.nativeapp.codegen.snowpark.extension_function_utils import (
38
- deannotate_module_source,
39
- ensure_all_string_literals,
40
- ensure_string_literal,
41
- get_function_type_signature_for_grant,
42
- get_qualified_object_name,
43
- get_sql_argument_signature,
44
- get_sql_object_type,
45
- )
46
- from snowflake.cli._plugins.nativeapp.codegen.snowpark.models import (
47
- ExtensionFunctionTypeEnum,
48
- NativeAppExtensionFunction,
49
- )
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
59
-
60
- DEFAULT_TIMEOUT = 30
61
- TEMPLATE_PATH = Path(__file__).parent / "callback_source.py.jinja"
62
- SNOWPARK_LIB_NAME = "snowflake-snowpark-python"
63
- SNOWPARK_LIB_REGEX = re.compile(
64
- # support PEP 508, even though not all of it is supported in Snowflake yet
65
- rf"'{SNOWPARK_LIB_NAME}\s*((<|<=|!=|==|>=|>|~=|===)\s*[a-zA-Z0-9_.*+!-]+)?'"
66
- )
67
- STAGE_PREFIX = "@"
68
-
69
-
70
- def _determine_virtual_env(
71
- project_root: Path, processor: ProcessorMapping
72
- ) -> Dict[str, Any]:
73
- """
74
- Determines a virtual environment to run the Snowpark processor in, either through the project definition or by querying the current environment.
75
- """
76
- if (processor.properties is None) or ("env" not in processor.properties):
77
- return {}
78
-
79
- env_props = processor.properties["env"]
80
- env_type = env_props.get("type", None)
81
-
82
- if env_type is None:
83
- return {}
84
-
85
- if env_type.upper() == ExecutionEnvironmentType.CONDA.name:
86
- env_name = env_props.get("name", None)
87
- if env_name is None:
88
- cc.warning(
89
- "No name found in project definition file for the conda environment to run the Snowpark processor in. Will attempt to auto-detect the current conda environment."
90
- )
91
- return {"env_type": ExecutionEnvironmentType.CONDA, "name": env_name}
92
- elif env_type.upper() == ExecutionEnvironmentType.VENV.name:
93
- env_path_str = env_props.get("path", None)
94
- if env_path_str is None:
95
- cc.warning(
96
- "No path found in project definition file for the conda environment to run the Snowpark processor in. Will attempt to auto-detect the current venv path."
97
- )
98
- env_path = None
99
- else:
100
- env_path = Path(env_path_str)
101
- if not env_path.is_absolute():
102
- env_path = project_root / env_path
103
- return {
104
- "env_type": ExecutionEnvironmentType.VENV,
105
- "path": env_path,
106
- }
107
- elif env_type.upper() == ExecutionEnvironmentType.CURRENT.name:
108
- return {
109
- "env_type": ExecutionEnvironmentType.CURRENT,
110
- }
111
- return {}
112
-
113
-
114
- def _is_python_file_artifact(src: Path, dest: Path):
115
- return src.is_file() and src.suffix == ".py"
116
-
117
-
118
- def _execute_in_sandbox(
119
- py_file: str, deploy_root: Path, kwargs: Dict[str, Any]
120
- ) -> Optional[List[Dict[str, Any]]]:
121
- # Create the code snippet to be executed in the sandbox
122
- script_source = jinja_render_from_file(
123
- template_path=TEMPLATE_PATH, data={"py_file": py_file}
124
- )
125
-
126
- try:
127
- completed_process = execute_script_in_sandbox(
128
- script_source=script_source,
129
- cwd=deploy_root,
130
- timeout=DEFAULT_TIMEOUT,
131
- **kwargs,
132
- )
133
- except SandboxExecutionError as sdbx_err:
134
- cc.warning(
135
- f"Could not fetch Snowpark objects from {py_file} due to {sdbx_err}, continuing execution for the rest of the python files."
136
- )
137
- return None
138
- except Exception as err:
139
- cc.warning(
140
- f"Could not fetch Snowpark objects from {py_file} due to {err}, continuing execution for the rest of the python files."
141
- )
142
- return None
143
-
144
- if completed_process.returncode != 0:
145
- cc.warning(
146
- f"Could not fetch Snowpark objects from {py_file} due to the following error:\n {completed_process.stderr}"
147
- )
148
- cc.warning("Continuing execution for the rest of the python files.")
149
- return None
150
-
151
- try:
152
- return json.loads(completed_process.stdout)
153
- except Exception as exc:
154
- cc.warning(
155
- f"Could not load JSON into python due to the following exception: {exc}"
156
- )
157
- cc.warning(f"Continuing execution for the rest of the python files.")
158
- return None
159
-
160
-
161
- class SnowparkAnnotationProcessor(ArtifactProcessor):
162
- """
163
- Built-in Processor to discover Snowpark-annotated objects in a given set of python files,
164
- and generate SQL code for creation of extension functions based on those discovered objects.
165
- """
166
-
167
- def __init__(self, *args, **kwargs):
168
- super().__init__(*args, **kwargs)
169
-
170
- def process(
171
- self,
172
- artifact_to_process: PathMapping,
173
- processor_mapping: Optional[ProcessorMapping],
174
- **kwargs,
175
- ) -> None:
176
- """
177
- Collects code annotations from Snowpark python files containing extension functions and augments the existing
178
- setup script with generated SQL that registers these functions.
179
- """
180
-
181
- get_cli_context().metrics.set_counter(CLICounterField.SNOWPARK_PROCESSOR, 1)
182
-
183
- bundle_map = BundleMap(
184
- project_root=self._bundle_ctx.project_root,
185
- deploy_root=self._bundle_ctx.deploy_root,
186
- )
187
- bundle_map.add(artifact_to_process)
188
-
189
- collected_extension_functions_by_path = self.collect_extension_functions(
190
- bundle_map, processor_mapping
191
- )
192
-
193
- collected_output = []
194
- collected_sql_files: List[Path] = []
195
- for py_file, extension_fns in sorted(
196
- collected_extension_functions_by_path.items()
197
- ):
198
- sql_file = self.generate_new_sql_file_name(
199
- py_file=py_file,
200
- )
201
- collected_sql_files.append(sql_file)
202
- insert_newline = False
203
- for extension_fn in extension_fns:
204
- create_stmt = generate_create_sql_ddl_statement(extension_fn)
205
- if create_stmt is None:
206
- continue
207
-
208
- relative_py_file = py_file.relative_to(bundle_map.deploy_root())
209
-
210
- grant_statements = generate_grant_sql_ddl_statements(extension_fn)
211
- if grant_statements is not None:
212
- collected_output.append(grant_statements)
213
-
214
- with open(sql_file, "a") as file:
215
- if insert_newline:
216
- file.write("\n")
217
- insert_newline = True
218
- file.write(
219
- f"-- Generated by the Snowflake CLI from {relative_py_file}\n"
220
- )
221
- file.write(f"-- DO NOT EDIT\n")
222
- file.write(create_stmt)
223
- if grant_statements is not None:
224
- file.write("\n")
225
- file.write(grant_statements)
226
-
227
- self.deannotate(py_file, extension_fns)
228
-
229
- if collected_sql_files:
230
- edit_setup_script_with_exec_imm_sql(
231
- collected_sql_files=collected_sql_files,
232
- deploy_root=bundle_map.deploy_root(),
233
- generated_root=self._bundle_ctx.generated_root,
234
- )
235
-
236
- def _normalize_imports(
237
- self,
238
- extension_fn: NativeAppExtensionFunction,
239
- py_file: Path,
240
- deploy_root: Path,
241
- ):
242
- normalized_imports: Set[str] = set()
243
- # Add the py_file, which is the source of the extension function
244
- normalized_imports.add(f"/{to_stage_path(py_file)}")
245
-
246
- for raw_import in extension_fn.imports:
247
- if not Path(deploy_root, raw_import).exists():
248
- # This should capture import_str of different forms: stagenames, malformed paths etc
249
- # But this will also return True if import_str == "/". Regardless, we append it all to normalized_imports
250
- cc.warning(
251
- f"{raw_import} does not exist in the deploy root. Skipping validation of this import."
252
- )
253
-
254
- if raw_import.startswith(STAGE_PREFIX) or raw_import.startswith("/"):
255
- normalized_imports.add(raw_import)
256
- else:
257
- normalized_imports.add(f"/{to_stage_path(Path(raw_import))}")
258
-
259
- # To ensure order when running tests
260
- sorted_imports = list(normalized_imports)
261
- sorted_imports.sort()
262
- extension_fn.imports = sorted_imports
263
-
264
- def _normalize(
265
- self,
266
- extension_fn: NativeAppExtensionFunction,
267
- py_file: Path,
268
- deploy_root: Path,
269
- ):
270
- if extension_fn.name is None:
271
- # The extension function was not named explicitly, use the name of the Python function object as its name
272
- extension_fn.name = extension_fn.handler
273
-
274
- # Compute the fully qualified handler
275
- # If user defined their udf as @udf(lambda: x, ...) then extension_fn.handler is <lambda>.
276
- extension_fn.handler = f"{py_file.stem}.{extension_fn.handler}"
277
-
278
- extension_fn.packages = [
279
- self._normalize_package_name(pkg) for pkg in extension_fn.packages
280
- ]
281
- snowpark_lib_name = ensure_string_literal(SNOWPARK_LIB_NAME)
282
- if snowpark_lib_name not in extension_fn.packages:
283
- extension_fn.packages.append(snowpark_lib_name)
284
-
285
- if extension_fn.imports is None:
286
- extension_fn.imports = []
287
- self._normalize_imports(
288
- extension_fn=extension_fn,
289
- py_file=py_file,
290
- deploy_root=deploy_root,
291
- )
292
-
293
- def _normalize_package_name(self, pkg: str) -> str:
294
- """
295
- Returns a normalized version of the provided package name, as a Snowflake SQL string literal. Since the
296
- Snowpark library can sometimes add a spurious version to its own package name, we strip this here too so
297
- that the native application does not accidentally rely on stale packages once the snowpark library is updated
298
- in the cloud.
299
-
300
- Args:
301
- pkg (str): The package name to normalize.
302
- Returns:
303
- A normalized version of the package name, as a Snowflake SQL string literal.
304
- """
305
- normalized_package_name = ensure_string_literal(pkg.strip())
306
- if SNOWPARK_LIB_REGEX.fullmatch(normalized_package_name):
307
- return ensure_string_literal(SNOWPARK_LIB_NAME)
308
- return normalized_package_name
309
-
310
- def collect_extension_functions(
311
- self, bundle_map: BundleMap, processor_mapping: Optional[ProcessorMapping]
312
- ) -> Dict[Path, List[NativeAppExtensionFunction]]:
313
- kwargs = (
314
- _determine_virtual_env(self._bundle_ctx.project_root, processor_mapping)
315
- if processor_mapping is not None
316
- else {}
317
- )
318
-
319
- collected_extension_fns_by_path: Dict[
320
- Path, List[NativeAppExtensionFunction]
321
- ] = {}
322
-
323
- for src_file, dest_file in sorted(
324
- bundle_map.all_mappings(
325
- absolute=True,
326
- expand_directories=True,
327
- predicate=is_python_file_artifact,
328
- )
329
- ):
330
- src_file_name = src_file.relative_to(self._bundle_ctx.project_root)
331
- cc.step(f"Processing Snowpark annotations from {src_file_name}")
332
- collected_extension_function_json = _execute_in_sandbox(
333
- py_file=str(dest_file.resolve()),
334
- deploy_root=self._bundle_ctx.deploy_root,
335
- kwargs=kwargs,
336
- )
337
-
338
- if collected_extension_function_json is None:
339
- continue
340
-
341
- collected_extension_functions = []
342
- for extension_function_json in collected_extension_function_json:
343
- try:
344
- extension_fn = NativeAppExtensionFunction(**extension_function_json)
345
- self._normalize(
346
- extension_fn,
347
- py_file=dest_file.relative_to(bundle_map.deploy_root()),
348
- deploy_root=bundle_map.deploy_root(),
349
- )
350
- collected_extension_functions.append(extension_fn)
351
- except ValidationError:
352
- cc.warning("Invalid extension function definition")
353
-
354
- if collected_extension_functions:
355
- collected_extension_fns_by_path[
356
- dest_file
357
- ] = collected_extension_functions
358
-
359
- return collected_extension_fns_by_path
360
-
361
- def generate_new_sql_file_name(self, py_file: Path) -> Path:
362
- """
363
- Generates a SQL filename for the generated root from the python file, and creates its parent directories.
364
- """
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
- )
369
- if sql_file.exists():
370
- cc.warning(
371
- f"""\
372
- File {sql_file} already exists, will append SQL statements to this file.
373
- """
374
- )
375
- sql_file.parent.mkdir(exist_ok=True, parents=True)
376
- return sql_file
377
-
378
- def deannotate(
379
- self, py_file: Path, extension_fns: List[NativeAppExtensionFunction]
380
- ):
381
- with open(py_file, "r", encoding="utf-8") as f:
382
- code = f.read()
383
-
384
- if py_file.is_symlink():
385
- # if the file is a symlink, make sure we don't overwrite the original
386
- py_file.unlink()
387
-
388
- new_code = deannotate_module_source(code, extension_fns)
389
-
390
- with open(py_file, "w", encoding="utf-8") as f:
391
- f.write(new_code)
392
-
393
-
394
- def generate_create_sql_ddl_statement(
395
- extension_fn: NativeAppExtensionFunction,
396
- ) -> Optional[str]:
397
- """
398
- Generates a "CREATE FUNCTION/PROCEDURE ... " SQL DDL statement based on an extension function definition.
399
- Logic for this create statement has been lifted from snowflake-snowpark-python v1.15.0 package.
400
- """
401
-
402
- object_type = get_sql_object_type(extension_fn)
403
- if object_type is None:
404
- cc.warning(f"Unsupported extension function type: {extension_fn.function_type}")
405
- return None
406
-
407
- arguments_in_sql = ", ".join(
408
- [get_sql_argument_signature(arg) for arg in extension_fn.signature]
409
- )
410
-
411
- create_query = dedent(
412
- f"""
413
- CREATE OR REPLACE
414
- {object_type} {get_qualified_object_name(extension_fn)}({arguments_in_sql})
415
- RETURNS {extension_fn.returns}
416
- LANGUAGE PYTHON
417
- RUNTIME_VERSION={extension_fn.runtime}
418
- """
419
- ).strip()
420
-
421
- if extension_fn.imports:
422
- create_query += (
423
- f"\nIMPORTS=({', '.join(ensure_all_string_literals(extension_fn.imports))})"
424
- )
425
-
426
- if extension_fn.packages:
427
- create_query += f"\nPACKAGES=({', '.join(ensure_all_string_literals([pkg.strip() for pkg in extension_fn.packages]))})"
428
-
429
- if extension_fn.external_access_integrations:
430
- create_query += f"\nEXTERNAL_ACCESS_INTEGRATIONS=({', '.join(ensure_all_string_literals(extension_fn.external_access_integrations))})"
431
-
432
- if extension_fn.secrets:
433
- create_query += f"""\nSECRETS=({', '.join([f"{ensure_string_literal(k)}={v}" for k, v in extension_fn.secrets.items()])})"""
434
-
435
- create_query += f"\nHANDLER={ensure_string_literal(extension_fn.handler)}"
436
-
437
- if extension_fn.function_type == ExtensionFunctionTypeEnum.PROCEDURE:
438
- if extension_fn.execute_as_caller:
439
- create_query += f"\nEXECUTE AS CALLER"
440
- else:
441
- create_query += f"\nEXECUTE AS OWNER"
442
- create_query += ";\n"
443
-
444
- return create_query
445
-
446
-
447
- def generate_grant_sql_ddl_statements(
448
- extension_fn: NativeAppExtensionFunction,
449
- ) -> Optional[str]:
450
- """
451
- Generates a "GRANT USAGE TO ... " SQL DDL statement based on a dictionary of extension function properties.
452
- If no application roles are present, then the function returns None.
453
- """
454
-
455
- if not extension_fn.application_roles:
456
- cc.warning(
457
- f"Skipping generation of 'GRANT USAGE ON ...' SQL statement for {extension_fn.function_type.upper()} {extension_fn.handler} due to lack of application roles."
458
- )
459
- return None
460
-
461
- grant_sql_statements = []
462
- object_type = (
463
- "PROCEDURE"
464
- if extension_fn.function_type == ExtensionFunctionTypeEnum.PROCEDURE
465
- else "FUNCTION"
466
- )
467
- for app_role in extension_fn.application_roles:
468
- grant_sql_statement = dedent(
469
- f"""\
470
- GRANT USAGE ON {object_type} {get_qualified_object_name(extension_fn)}({get_function_type_signature_for_grant(extension_fn)})
471
- TO APPLICATION ROLE {app_role};
472
- """
473
- ).strip()
474
- grant_sql_statements.append(grant_sql_statement)
475
-
476
- return "\n".join(grant_sql_statements)
477
-
478
-
479
- def edit_setup_script_with_exec_imm_sql(
480
- collected_sql_files: List[Path], deploy_root: Path, generated_root: Path
481
- ):
482
- """
483
- Adds an 'execute immediate' to setup script for every SQL file in the map
484
- """
485
- # Create a __generated.sql in the __generated folder
486
- generated_file_path = Path(generated_root, f"__generated.sql")
487
- generated_file_path.parent.mkdir(exist_ok=True, parents=True)
488
-
489
- if generated_file_path.exists():
490
- cc.warning(
491
- f"""\
492
- File {generated_file_path} already exists.
493
- Could not complete code generation of Snowpark Extension Functions.
494
- """
495
- )
496
- return
497
-
498
- # For every SQL file, add SQL statement 'execute immediate' to __generated.sql script.
499
- with open(generated_file_path, "a") as file:
500
- for sql_file in collected_sql_files:
501
- sql_file_relative_path = sql_file.relative_to(
502
- deploy_root
503
- ) # Path on stage, without the leading slash
504
- file.write(
505
- f"EXECUTE IMMEDIATE FROM '/{to_stage_path(sql_file_relative_path)}';\n"
506
- )
507
-
508
- # Find the setup script in the deploy root.
509
- setup_file_path = find_setup_script_file(deploy_root=deploy_root)
510
- with open(setup_file_path, "r", encoding="utf-8") as file:
511
- code = file.read()
512
- # Unlink to prevent over-writing source file
513
- if setup_file_path.is_symlink():
514
- setup_file_path.unlink()
515
-
516
- # Write original contents and the execute immediate sql to the setup script
517
- generated_file_relative_path = generated_file_path.relative_to(deploy_root)
518
- with open(setup_file_path, "w", encoding="utf-8") as file:
519
- file.write(code)
520
- file.write(
521
- f"\nEXECUTE IMMEDIATE FROM '/{to_stage_path(generated_file_relative_path)}';"
522
- )
523
- file.write(f"\n")
@@ -1,114 +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 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)