snowflake-cli-labs 2.8.0rc0__py3-none-any.whl → 3.0.0rc0__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 (220) 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 +12 -12
  4. snowflake/cli/{app → _app}/commands_registration/builtin_plugins.py +13 -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 → _app}/snow_connector.py +6 -6
  16. snowflake/cli/{app → _app}/telemetry.py +4 -5
  17. snowflake/cli/{plugins → _plugins}/connection/commands.py +22 -5
  18. snowflake/cli/_plugins/connection/plugin_spec.py +30 -0
  19. snowflake/cli/{plugins → _plugins}/connection/util.py +16 -0
  20. snowflake/cli/{plugins → _plugins}/cortex/commands.py +54 -49
  21. snowflake/cli/{plugins → _plugins}/cortex/constants.py +1 -1
  22. snowflake/cli/{plugins → _plugins}/cortex/manager.py +5 -5
  23. snowflake/cli/{plugins → _plugins}/cortex/plugin_spec.py +1 -1
  24. snowflake/cli/{plugins → _plugins}/git/commands.py +32 -20
  25. snowflake/cli/{plugins → _plugins}/git/manager.py +6 -5
  26. snowflake/cli/{plugins → _plugins}/git/plugin_spec.py +1 -1
  27. snowflake/cli/{plugins → _plugins}/init/commands.py +10 -6
  28. snowflake/cli/{plugins → _plugins}/init/plugin_spec.py +1 -1
  29. snowflake/cli/{plugins → _plugins}/nativeapp/artifacts.py +14 -0
  30. snowflake/cli/_plugins/nativeapp/bundle_context.py +31 -0
  31. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/artifact_processor.py +3 -3
  32. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/compiler.py +16 -18
  33. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/setup/native_app_setup_processor.py +24 -28
  34. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/extension_function_utils.py +4 -4
  35. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/python_processor.py +20 -24
  36. snowflake/cli/{plugins → _plugins}/nativeapp/commands.py +171 -42
  37. snowflake/cli/{plugins → _plugins}/nativeapp/common_flags.py +1 -1
  38. snowflake/cli/{plugins → _plugins}/nativeapp/init.py +1 -1
  39. snowflake/cli/_plugins/nativeapp/manager.py +601 -0
  40. snowflake/cli/{plugins/connection → _plugins/nativeapp}/plugin_spec.py +1 -1
  41. snowflake/cli/{plugins → _plugins}/nativeapp/project_model.py +34 -11
  42. snowflake/cli/{plugins → _plugins}/nativeapp/run_processor.py +25 -23
  43. snowflake/cli/{plugins → _plugins}/nativeapp/teardown_processor.py +8 -8
  44. snowflake/cli/{plugins → _plugins}/nativeapp/v2_conversions/v2_to_v1_decorator.py +47 -28
  45. snowflake/cli/{plugins → _plugins}/nativeapp/version/commands.py +15 -12
  46. snowflake/cli/{plugins → _plugins}/nativeapp/version/version_processor.py +22 -20
  47. snowflake/cli/{plugins → _plugins}/notebook/commands.py +8 -6
  48. snowflake/cli/{plugins → _plugins}/notebook/manager.py +14 -14
  49. snowflake/cli/{plugins → _plugins}/notebook/plugin_spec.py +1 -1
  50. snowflake/cli/{plugins → _plugins}/notebook/types.py +0 -1
  51. snowflake/cli/{plugins → _plugins}/object/command_aliases.py +6 -5
  52. snowflake/cli/{plugins → _plugins}/object/commands.py +16 -10
  53. snowflake/cli/{plugins → _plugins}/object/manager.py +7 -6
  54. snowflake/cli/{plugins → _plugins}/object/plugin_spec.py +1 -1
  55. snowflake/cli/_plugins/snowpark/commands.py +510 -0
  56. snowflake/cli/_plugins/snowpark/common.py +252 -0
  57. snowflake/cli/{plugins → _plugins}/snowpark/models.py +0 -7
  58. snowflake/cli/{plugins → _plugins}/snowpark/package/anaconda_packages.py +1 -1
  59. snowflake/cli/{plugins → _plugins}/snowpark/package/commands.py +13 -74
  60. snowflake/cli/{plugins → _plugins}/snowpark/package/manager.py +4 -3
  61. snowflake/cli/{plugins → _plugins}/snowpark/package_utils.py +5 -5
  62. snowflake/cli/{plugins/nativeapp → _plugins/snowpark}/plugin_spec.py +1 -1
  63. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +109 -0
  64. snowflake/cli/{plugins → _plugins}/snowpark/snowpark_shared.py +0 -36
  65. snowflake/cli/{plugins → _plugins}/snowpark/zipper.py +16 -8
  66. snowflake/cli/{plugins → _plugins}/spcs/__init__.py +5 -7
  67. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/commands.py +29 -28
  68. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/manager.py +3 -3
  69. snowflake/cli/{plugins → _plugins}/spcs/image_registry/commands.py +3 -3
  70. snowflake/cli/{plugins → _plugins}/spcs/image_repository/commands.py +25 -19
  71. snowflake/cli/{plugins → _plugins}/spcs/image_repository/manager.py +1 -1
  72. snowflake/cli/{plugins → _plugins}/spcs/plugin_spec.py +1 -1
  73. snowflake/cli/{plugins → _plugins}/spcs/services/commands.py +66 -32
  74. snowflake/cli/{plugins → _plugins}/spcs/services/manager.py +43 -5
  75. snowflake/cli/{plugins → _plugins}/sql/commands.py +19 -15
  76. snowflake/cli/{plugins → _plugins}/sql/manager.py +1 -1
  77. snowflake/cli/{plugins → _plugins}/sql/plugin_spec.py +1 -1
  78. snowflake/cli/{plugins → _plugins}/stage/commands.py +20 -17
  79. snowflake/cli/{plugins → _plugins}/stage/diff.py +1 -47
  80. snowflake/cli/{plugins → _plugins}/stage/manager.py +8 -6
  81. snowflake/cli/{plugins → _plugins}/stage/plugin_spec.py +1 -1
  82. snowflake/cli/_plugins/stage/utils.py +54 -0
  83. snowflake/cli/_plugins/streamlit/commands.py +242 -0
  84. snowflake/cli/{plugins → _plugins}/streamlit/manager.py +47 -70
  85. snowflake/cli/_plugins/streamlit/plugin_spec.py +30 -0
  86. snowflake/cli/_plugins/workspace/action_context.py +11 -0
  87. snowflake/cli/_plugins/workspace/commands.py +113 -0
  88. snowflake/cli/_plugins/workspace/manager.py +57 -0
  89. snowflake/cli/{plugins → _plugins}/workspace/plugin_spec.py +1 -1
  90. snowflake/cli/api/cli_global_context.py +34 -7
  91. snowflake/cli/api/commands/common.py +25 -0
  92. snowflake/cli/api/commands/decorators.py +4 -3
  93. snowflake/cli/api/commands/experimental_behaviour.py +2 -3
  94. snowflake/cli/api/commands/flags.py +73 -174
  95. snowflake/cli/api/commands/overrideable_parameter.py +143 -0
  96. snowflake/cli/api/commands/snow_typer.py +5 -4
  97. snowflake/cli/api/commands/typer_pre_execute.py +3 -3
  98. snowflake/cli/api/commands/utils.py +18 -0
  99. snowflake/cli/api/config.py +1 -1
  100. snowflake/cli/api/console/abc.py +5 -2
  101. snowflake/cli/api/entities/application_entity.py +12 -0
  102. snowflake/cli/api/entities/application_package_entity.py +260 -0
  103. snowflake/cli/api/entities/common.py +47 -0
  104. snowflake/cli/api/entities/snowpark_entity.py +29 -0
  105. snowflake/cli/api/entities/streamlit_entity.py +12 -0
  106. snowflake/cli/api/entities/utils.py +321 -0
  107. snowflake/cli/api/exceptions.py +19 -3
  108. snowflake/cli/api/feature_flags.py +2 -1
  109. snowflake/cli/api/identifiers.py +41 -9
  110. snowflake/cli/api/project/definition.py +13 -5
  111. snowflake/cli/api/project/definition_manager.py +12 -1
  112. snowflake/cli/api/project/errors.py +16 -1
  113. snowflake/cli/api/project/project_verification.py +3 -3
  114. snowflake/cli/api/project/schemas/entities/{application_entity.py → application_entity_model.py} +21 -9
  115. snowflake/cli/api/project/schemas/entities/{application_package_entity.py → application_package_entity_model.py} +26 -15
  116. snowflake/cli/api/project/schemas/entities/common.py +80 -6
  117. snowflake/cli/api/project/schemas/entities/entities.py +38 -8
  118. snowflake/cli/api/project/schemas/entities/snowpark_entity.py +176 -0
  119. snowflake/cli/api/project/schemas/entities/streamlit_entity_model.py +73 -0
  120. snowflake/cli/api/project/schemas/identifier_model.py +10 -1
  121. snowflake/cli/api/project/schemas/native_app/application.py +8 -9
  122. snowflake/cli/api/project/schemas/native_app/package.py +7 -1
  123. snowflake/cli/api/project/schemas/project_definition.py +97 -23
  124. snowflake/cli/api/project/schemas/updatable_model.py +11 -3
  125. snowflake/cli/api/project/util.py +23 -6
  126. snowflake/cli/api/rendering/jinja.py +28 -8
  127. snowflake/cli/api/rendering/sql_templates.py +41 -12
  128. snowflake/cli/api/secure_path.py +3 -0
  129. snowflake/cli/api/sql_execution.py +35 -19
  130. snowflake/cli/api/utils/definition_rendering.py +14 -2
  131. {snowflake_cli_labs-2.8.0rc0.dist-info → snowflake_cli_labs-3.0.0rc0.dist-info}/METADATA +12 -12
  132. snowflake_cli_labs-3.0.0rc0.dist-info/RECORD +234 -0
  133. snowflake_cli_labs-3.0.0rc0.dist-info/entry_points.txt +2 -0
  134. snowflake/cli/api/commands/project_initialisation.py +0 -65
  135. snowflake/cli/app/build_and_push.sh +0 -8
  136. snowflake/cli/plugins/nativeapp/manager.py +0 -819
  137. snowflake/cli/plugins/object_stage_deprecated/__init__.py +0 -15
  138. snowflake/cli/plugins/object_stage_deprecated/commands.py +0 -122
  139. snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +0 -32
  140. snowflake/cli/plugins/snowpark/commands.py +0 -548
  141. snowflake/cli/plugins/snowpark/common.py +0 -307
  142. snowflake/cli/plugins/snowpark/manager.py +0 -109
  143. snowflake/cli/plugins/snowpark/plugin_spec.py +0 -30
  144. snowflake/cli/plugins/snowpark/snowpark_package_paths.py +0 -65
  145. snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
  146. snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
  147. snowflake/cli/plugins/streamlit/commands.py +0 -186
  148. snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
  149. snowflake/cli/plugins/workspace/commands.py +0 -35
  150. snowflake/cli/templates/default_snowpark/.gitignore +0 -4
  151. snowflake/cli/templates/default_snowpark/app/__init__.py +0 -0
  152. snowflake/cli/templates/default_snowpark/app/common.py +0 -2
  153. snowflake/cli/templates/default_snowpark/app/functions.py +0 -15
  154. snowflake/cli/templates/default_snowpark/app/procedures.py +0 -22
  155. snowflake/cli/templates/default_snowpark/requirements.txt +0 -1
  156. snowflake/cli/templates/default_snowpark/snowflake.yml +0 -23
  157. snowflake/cli/templates/default_streamlit/.gitignore +0 -4
  158. snowflake/cli/templates/default_streamlit/common/hello.py +0 -2
  159. snowflake/cli/templates/default_streamlit/environment.yml +0 -6
  160. snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -3
  161. snowflake/cli/templates/default_streamlit/snowflake.yml +0 -10
  162. snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -4
  163. snowflake_cli_labs-2.8.0rc0.dist-info/RECORD +0 -240
  164. snowflake_cli_labs-2.8.0rc0.dist-info/entry_points.txt +0 -2
  165. /snowflake/cli/{app → _app}/__init__.py +0 -0
  166. /snowflake/cli/{app → _app}/api_impl/__init__.py +0 -0
  167. /snowflake/cli/{app → _app}/api_impl/plugin/__init__.py +0 -0
  168. /snowflake/cli/{app → _app}/api_impl/plugin/plugin_config_provider_impl.py +0 -0
  169. /snowflake/cli/{app → _app}/commands_registration/__init__.py +0 -0
  170. /snowflake/cli/{app → _app}/commands_registration/threadsafe.py +0 -0
  171. /snowflake/cli/{app → _app}/constants.py +0 -0
  172. /snowflake/cli/{app → _app}/dev/__init__.py +0 -0
  173. /snowflake/cli/{app → _app}/dev/commands_structure.py +0 -0
  174. /snowflake/cli/{app → _app}/dev/docs/__init__.py +0 -0
  175. /snowflake/cli/{app → _app}/dev/docs/project_definition_generate_json_schema.py +0 -0
  176. /snowflake/cli/{app → _app}/dev/docs/template_utils.py +0 -0
  177. /snowflake/cli/{app → _app}/dev/docs/templates/definition_description.rst.jinja2 +0 -0
  178. /snowflake/cli/{app → _app}/dev/docs/templates/overview.rst.jinja2 +0 -0
  179. /snowflake/cli/{app → _app}/dev/pycharm_remote_debug.py +0 -0
  180. /snowflake/cli/{app → _app}/loggers.py +0 -0
  181. /snowflake/cli/{plugins → _plugins}/__init__.py +0 -0
  182. /snowflake/cli/{plugins → _plugins}/connection/__init__.py +0 -0
  183. /snowflake/cli/{plugins → _plugins}/cortex/__init__.py +0 -0
  184. /snowflake/cli/{plugins → _plugins}/cortex/types.py +0 -0
  185. /snowflake/cli/{plugins → _plugins}/git/__init__.py +0 -0
  186. /snowflake/cli/{plugins → _plugins}/init/__init__.py +0 -0
  187. /snowflake/cli/{plugins → _plugins}/nativeapp/__init__.py +0 -0
  188. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/__init__.py +0 -0
  189. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/sandbox.py +0 -0
  190. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/setup/setup_driver.py.source +0 -0
  191. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -0
  192. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/models.py +0 -0
  193. /snowflake/cli/{plugins → _plugins}/nativeapp/constants.py +0 -0
  194. /snowflake/cli/{plugins → _plugins}/nativeapp/exceptions.py +0 -0
  195. /snowflake/cli/{plugins → _plugins}/nativeapp/feature_flags.py +0 -0
  196. /snowflake/cli/{plugins → _plugins}/nativeapp/policy.py +0 -0
  197. /snowflake/cli/{plugins → _plugins}/nativeapp/utils.py +0 -0
  198. /snowflake/cli/{plugins → _plugins}/nativeapp/version/__init__.py +0 -0
  199. /snowflake/cli/{plugins → _plugins}/notebook/__init__.py +0 -0
  200. /snowflake/cli/{plugins → _plugins}/notebook/exceptions.py +0 -0
  201. /snowflake/cli/{plugins → _plugins}/object/__init__.py +0 -0
  202. /snowflake/cli/{plugins → _plugins}/object/common.py +0 -0
  203. /snowflake/cli/{plugins → _plugins}/snowpark/__init__.py +0 -0
  204. /snowflake/cli/{plugins → _plugins}/snowpark/package/__init__.py +0 -0
  205. /snowflake/cli/{plugins → _plugins}/snowpark/package/utils.py +0 -0
  206. /snowflake/cli/{plugins → _plugins}/spcs/common.py +0 -0
  207. /snowflake/cli/{plugins → _plugins}/spcs/compute_pool/__init__.py +0 -0
  208. /snowflake/cli/{plugins → _plugins}/spcs/image_registry/__init__.py +0 -0
  209. /snowflake/cli/{plugins → _plugins}/spcs/image_registry/manager.py +0 -0
  210. /snowflake/cli/{plugins → _plugins}/spcs/image_repository/__init__.py +0 -0
  211. /snowflake/cli/{plugins/spcs/jobs → _plugins/spcs/services}/__init__.py +0 -0
  212. /snowflake/cli/{plugins/spcs/services → _plugins/sql}/__init__.py +0 -0
  213. /snowflake/cli/{plugins → _plugins}/sql/snowsql_templating.py +0 -0
  214. /snowflake/cli/{plugins/sql → _plugins/stage}/__init__.py +0 -0
  215. /snowflake/cli/{plugins → _plugins}/stage/md5.py +0 -0
  216. /snowflake/cli/{plugins/stage → _plugins/streamlit}/__init__.py +0 -0
  217. /snowflake/cli/{plugins/streamlit → _plugins/workspace}/__init__.py +0 -0
  218. /snowflake/cli/{plugins/workspace → api/project/schemas/entities}/__init__.py +0 -0
  219. {snowflake_cli_labs-2.8.0rc0.dist-info → snowflake_cli_labs-3.0.0rc0.dist-info}/WHEEL +0 -0
  220. {snowflake_cli_labs-2.8.0rc0.dist-info → snowflake_cli_labs-3.0.0rc0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,252 @@
1
+ # Copyright (c) 2024 Snowflake Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ import logging
18
+ import re
19
+ from enum import Enum
20
+ from typing import Dict, List, Set
21
+
22
+ from click import UsageError
23
+ from snowflake.cli._plugins.snowpark.models import Requirement
24
+ from snowflake.cli._plugins.snowpark.snowpark_project_paths import Artefact
25
+ from snowflake.cli.api.console import cli_console
26
+ from snowflake.cli.api.constants import ObjectType
27
+ from snowflake.cli.api.project.schemas.entities.snowpark_entity import (
28
+ ProcedureEntityModel,
29
+ SnowparkEntityModel,
30
+ )
31
+ from snowflake.cli.api.sql_execution import SqlExecutionMixin
32
+ from snowflake.connector.cursor import SnowflakeCursor
33
+
34
+ log = logging.getLogger(__name__)
35
+
36
+ SnowparkEntities = Dict[str, SnowparkEntityModel]
37
+ StageToArtefactMapping = Dict[str, set[Artefact]]
38
+ EntityToImportPathsMapping = Dict[str, set[str]]
39
+
40
+ DEFAULT_RUNTIME = "3.10"
41
+
42
+
43
+ class SnowparkObject(Enum):
44
+ """This clas is used only for Snowpark execute where choice is limited."""
45
+
46
+ PROCEDURE = str(ObjectType.PROCEDURE)
47
+ FUNCTION = str(ObjectType.FUNCTION)
48
+
49
+
50
+ class SnowparkObjectManager(SqlExecutionMixin):
51
+ def execute(
52
+ self, execution_identifier: str, object_type: SnowparkObject
53
+ ) -> SnowflakeCursor:
54
+ if object_type == SnowparkObject.FUNCTION:
55
+ return self._execute_query(f"select {execution_identifier}")
56
+ if object_type == SnowparkObject.PROCEDURE:
57
+ return self._execute_query(f"call {execution_identifier}")
58
+ raise UsageError(f"Unknown object type: {object_type}.")
59
+
60
+ def create_or_replace(
61
+ self,
62
+ entity: SnowparkEntityModel,
63
+ artifact_files: set[str],
64
+ snowflake_dependencies: list[str],
65
+ ) -> str:
66
+ entity.imports.extend(artifact_files)
67
+ imports = [f"'{x}'" for x in entity.imports]
68
+ packages_list = ",".join(f"'{p}'" for p in snowflake_dependencies)
69
+
70
+ object_type = entity.get_type()
71
+
72
+ query = [
73
+ f"create or replace {object_type} {entity.udf_sproc_identifier.identifier_for_sql}",
74
+ f"copy grants",
75
+ f"returns {entity.returns}",
76
+ "language python",
77
+ f"runtime_version={entity.runtime or DEFAULT_RUNTIME}",
78
+ f"imports=({', '.join(imports)})",
79
+ f"handler='{entity.handler}'",
80
+ f"packages=({packages_list})",
81
+ ]
82
+
83
+ if entity.external_access_integrations:
84
+ query.append(entity.get_external_access_integrations_sql())
85
+
86
+ if entity.secrets:
87
+ query.append(entity.get_secrets_sql())
88
+
89
+ if isinstance(entity, ProcedureEntityModel) and entity.execute_as_caller:
90
+ query.append("execute as caller")
91
+
92
+ return self._execute_query("\n".join(query))
93
+
94
+ def deploy_entity(
95
+ self,
96
+ entity: SnowparkEntityModel,
97
+ existing_objects: Dict[str, SnowflakeCursor],
98
+ snowflake_dependencies: List[str],
99
+ entities_to_artifact_map: EntityToImportPathsMapping,
100
+ ):
101
+ cli_console.step(f"Creating {entity.type} {entity.fqn}")
102
+ object_exists = entity.entity_id in existing_objects
103
+ replace_object = False
104
+ if object_exists:
105
+ replace_object = _check_if_replace_is_required(
106
+ entity=entity,
107
+ current_state=existing_objects[entity.entity_id],
108
+ snowflake_dependencies=snowflake_dependencies,
109
+ stage_artifact_files=entities_to_artifact_map[entity.entity_id],
110
+ )
111
+
112
+ state = {
113
+ "object": entity.udf_sproc_identifier.identifier_with_arg_names_types_defaults,
114
+ "type": entity.get_type(),
115
+ }
116
+ if object_exists and not replace_object:
117
+ return {**state, "status": "packages updated"}
118
+
119
+ self.create_or_replace(
120
+ entity=entity,
121
+ artifact_files=entities_to_artifact_map[entity.entity_id],
122
+ snowflake_dependencies=snowflake_dependencies,
123
+ )
124
+ return {
125
+ **state,
126
+ "status": "created" if not object_exists else "definition updated",
127
+ }
128
+
129
+
130
+ def _check_if_replace_is_required(
131
+ entity: SnowparkEntityModel,
132
+ current_state,
133
+ snowflake_dependencies: List[str],
134
+ stage_artifact_files: set[str],
135
+ ) -> bool:
136
+ object_type = entity.get_type()
137
+ resource_json = _convert_resource_details_to_dict(current_state)
138
+ old_dependencies = resource_json["packages"]
139
+
140
+ if _snowflake_dependencies_differ(old_dependencies, snowflake_dependencies):
141
+ log.info(
142
+ "Found difference of package requirements. Replacing the %s.", object_type
143
+ )
144
+ return True
145
+
146
+ if set(entity.external_access_integrations) != set(
147
+ resource_json.get("external_access_integrations", [])
148
+ ):
149
+ log.info(
150
+ "Found difference of external access integrations. Replacing the %s.",
151
+ object_type,
152
+ )
153
+ return True
154
+
155
+ if (
156
+ resource_json["handler"].lower() != entity.handler.lower()
157
+ or _sql_to_python_return_type_mapper(resource_json["returns"]).lower()
158
+ != entity.returns.lower()
159
+ ):
160
+ log.info(
161
+ "Return type or handler types do not match. Replacing the %s.", object_type
162
+ )
163
+ return True
164
+
165
+ if _compare_imports(resource_json, entity.imports, stage_artifact_files):
166
+ log.info("Imports do not match. Replacing the %s", object_type)
167
+ return True
168
+
169
+ if entity.runtime is not None and entity.runtime != resource_json.get(
170
+ "runtime_version", "RUNTIME_NOT_SET"
171
+ ):
172
+ log.info("Runtime versions do not match. Replacing the %s", object_type)
173
+ return True
174
+
175
+ if isinstance(entity, ProcedureEntityModel):
176
+ if resource_json.get("execute as", "OWNER") != (
177
+ "CALLER" if entity.execute_as_caller else "OWNER"
178
+ ):
179
+ log.info(
180
+ "Execute as caller settings do not match. Replacing the %s", object_type
181
+ )
182
+ return True
183
+
184
+ return False
185
+
186
+
187
+ def _convert_resource_details_to_dict(function_details: SnowflakeCursor) -> dict:
188
+ import json
189
+
190
+ function_dict = {}
191
+ json_properties = ["packages", "installed_packages"]
192
+ for function in function_details:
193
+ if function[0] in json_properties:
194
+ function_dict[function[0]] = json.loads(
195
+ function[1].replace("'", '"'),
196
+ )
197
+ else:
198
+ function_dict[function[0]] = function[1]
199
+ return function_dict
200
+
201
+
202
+ def _snowflake_dependencies_differ(
203
+ old_dependencies: List[str], new_dependencies: List[str]
204
+ ) -> bool:
205
+ def _standardize(packages: List[str]) -> Set[str]:
206
+ return set(
207
+ Requirement.parse_line(package).name_and_version for package in packages
208
+ )
209
+
210
+ return _standardize(old_dependencies) != _standardize(new_dependencies)
211
+
212
+
213
+ def _sql_to_python_return_type_mapper(resource_return_type: str) -> str:
214
+ """
215
+ Some of the Python data types get converted to SQL types, when function/procedure is created.
216
+ So, to properly compare types, we use mapping based on:
217
+ https://docs.snowflake.com/en/developer-guide/udf-stored-procedure-data-type-mapping#sql-python-data-type-mappings
218
+
219
+ Mind you, this only applies to cases, in which Snowflake accepts Python type as return.
220
+ Ie. if function returns list, it has to be declared as 'array' during creation,
221
+ therefore any conversion is not necessary
222
+ """
223
+ mapping = {
224
+ "number(38,0)": "int",
225
+ "timestamp_ntz(9)": "datetime",
226
+ "timestamp_tz(9)": "datetime",
227
+ "varchar(16777216)": "string",
228
+ }
229
+
230
+ return mapping.get(resource_return_type.lower(), resource_return_type.lower())
231
+
232
+
233
+ def _compare_imports(
234
+ resource_json: dict, imports: List[str], artifact_files: set[str]
235
+ ) -> bool:
236
+ pattern = re.compile(r"(?:\[@?\w+_\w+\.)?(\w+(?:/\w+)+\.\w+)(?:\])?")
237
+
238
+ project_imports = {
239
+ imp
240
+ for import_string in [*imports, *artifact_files]
241
+ for imp in pattern.findall(import_string.lower())
242
+ }
243
+
244
+ if "imports" not in resource_json.keys():
245
+ object_imports = set()
246
+ else:
247
+ object_imports = {
248
+ imp.lower()
249
+ for imp in pattern.findall(resource_json.get("imports", "").lower())
250
+ }
251
+
252
+ return project_imports != object_imports
@@ -17,19 +17,12 @@ from __future__ import annotations
17
17
  import re
18
18
  import zipfile
19
19
  from dataclasses import dataclass
20
- from enum import Enum
21
20
  from pathlib import Path
22
21
  from typing import List
23
22
 
24
23
  from requirements import requirement
25
24
 
26
25
 
27
- class YesNoAsk(Enum):
28
- YES = "yes"
29
- NO = "no"
30
- ASK = "ask"
31
-
32
-
33
26
  class Requirement(requirement.Requirement):
34
27
  extra_pattern = re.compile("'([^']*)'")
35
28
 
@@ -24,10 +24,10 @@ from packaging.requirements import InvalidRequirement
24
24
  from packaging.requirements import Requirement as PkgRequirement
25
25
  from packaging.version import InvalidVersion, parse
26
26
  from requests import HTTPError
27
+ from snowflake.cli._plugins.snowpark.models import Requirement
27
28
  from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
28
29
  from snowflake.cli.api.secure_path import SecurePath
29
30
  from snowflake.cli.api.sql_execution import SqlExecutionMixin
30
- from snowflake.cli.plugins.snowpark.models import Requirement
31
31
  from snowflake.connector import DictCursor
32
32
 
33
33
  log = logging.getLogger(__name__)
@@ -21,35 +21,29 @@ from typing import Optional
21
21
 
22
22
  import typer
23
23
  from click import ClickException
24
- from snowflake.cli.api.commands.flags import (
25
- deprecated_flag_callback,
26
- )
27
- from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
28
- from snowflake.cli.api.output.types import CommandResult, MessageResult
29
- from snowflake.cli.api.secure_path import SecurePath
30
- from snowflake.cli.plugins.snowpark.models import (
24
+ from snowflake.cli._plugins.snowpark.models import (
31
25
  Requirement,
32
- YesNoAsk,
33
26
  )
34
- from snowflake.cli.plugins.snowpark.package.anaconda_packages import (
27
+ from snowflake.cli._plugins.snowpark.package.anaconda_packages import (
35
28
  AnacondaPackages,
36
29
  AnacondaPackagesManager,
37
30
  )
38
- from snowflake.cli.plugins.snowpark.package.manager import upload
39
- from snowflake.cli.plugins.snowpark.package_utils import (
31
+ from snowflake.cli._plugins.snowpark.package.manager import upload
32
+ from snowflake.cli._plugins.snowpark.package_utils import (
40
33
  detect_and_log_shared_libraries,
41
34
  download_unavailable_packages,
42
35
  get_package_name_from_pip_wheel,
43
36
  )
44
- from snowflake.cli.plugins.snowpark.snowpark_shared import (
37
+ from snowflake.cli._plugins.snowpark.snowpark_shared import (
45
38
  AllowSharedLibrariesOption,
46
39
  IgnoreAnacondaOption,
47
40
  IndexUrlOption,
48
41
  SkipVersionCheckOption,
49
- deprecated_allow_native_libraries_option,
50
- resolve_allow_shared_libraries_yes_no_ask,
51
42
  )
52
- from snowflake.cli.plugins.snowpark.zipper import zip_dir
43
+ from snowflake.cli._plugins.snowpark.zipper import zip_dir
44
+ from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
45
+ from snowflake.cli.api.output.types import CommandResult, MessageResult
46
+ from snowflake.cli.api.secure_path import SecurePath
53
47
 
54
48
  app = SnowTyperFactory(
55
49
  name="package",
@@ -58,36 +52,11 @@ app = SnowTyperFactory(
58
52
  log = logging.getLogger(__name__)
59
53
 
60
54
 
61
- lookup_install_option = typer.Option(
62
- False,
63
- "--pypi-download",
64
- hidden=True,
65
- callback=deprecated_flag_callback(
66
- "Using --pypi-download is deprecated. Lookup command no longer checks for package in PyPi."
67
- ),
68
- help="Installs packages that are not available on the Snowflake Anaconda channel.",
69
- )
70
-
71
- lookup_deprecated_install_option = typer.Option(
72
- False,
73
- "--yes",
74
- "-y",
75
- hidden=True,
76
- callback=deprecated_flag_callback(
77
- "Using --yes is deprecated. Lookup command no longer checks for package in PyPi."
78
- ),
79
- help="Installs packages that are not available on the Snowflake Anaconda channel.",
80
- )
81
-
82
-
83
55
  @app.command("lookup", requires_connection=True)
84
56
  def package_lookup(
85
57
  package_name: str = typer.Argument(
86
58
  ..., help="Name of the package.", show_default=False
87
59
  ),
88
- # todo: remove with 3.0
89
- _: bool = lookup_install_option,
90
- __: bool = lookup_deprecated_install_option,
91
60
  **options,
92
61
  ) -> CommandResult:
93
62
  """
@@ -125,12 +94,14 @@ def package_upload(
125
94
  "-f",
126
95
  help="Path to the file to upload.",
127
96
  exists=False,
97
+ show_default=False,
128
98
  ),
129
99
  stage: str = typer.Option(
130
100
  ...,
131
101
  "--stage",
132
102
  "-s",
133
103
  help="Name of the stage in which to upload the file, not including the @ symbol.",
104
+ show_default=False,
134
105
  ),
135
106
  overwrite: bool = typer.Option(
136
107
  False,
@@ -146,43 +117,17 @@ def package_upload(
146
117
  return MessageResult(upload(file=file, stage=stage, overwrite=overwrite))
147
118
 
148
119
 
149
- deprecated_pypi_download_option = typer.Option(
150
- False,
151
- "--pypi-download",
152
- hidden=True,
153
- callback=deprecated_flag_callback(
154
- "Using --pypi-download is deprecated. Create command always checks for package in PyPi."
155
- ),
156
- help="Installs packages that are not available on the Snowflake Anaconda channel.",
157
- )
158
-
159
- deprecated_install_option = typer.Option(
160
- False,
161
- "--yes",
162
- "-y",
163
- hidden=True,
164
- help="Installs packages that are not available on the Snowflake Anaconda channel.",
165
- callback=deprecated_flag_callback(
166
- "Using --yes is deprecated. Create command always checks for package in PyPi."
167
- ),
168
- )
169
-
170
-
171
120
  @app.command("create", requires_connection=True)
172
121
  def package_create(
173
122
  name: str = typer.Argument(
174
123
  ...,
175
124
  help="Name of the package to create.",
125
+ show_default=False,
176
126
  ),
177
127
  ignore_anaconda: bool = IgnoreAnacondaOption,
178
128
  index_url: Optional[str] = IndexUrlOption,
179
129
  skip_version_check: bool = SkipVersionCheckOption,
180
130
  allow_shared_libraries: bool = AllowSharedLibrariesOption,
181
- deprecated_allow_native_libraries: YesNoAsk = deprecated_allow_native_libraries_option(
182
- "--allow-native-libraries"
183
- ),
184
- _deprecated_install_option: bool = deprecated_install_option,
185
- _deprecated_install_packages: bool = deprecated_pypi_download_option,
186
131
  **options,
187
132
  ) -> CommandResult:
188
133
  """
@@ -217,13 +162,7 @@ def package_create(
217
162
  # The package is not in anaconda, so we have to pack it
218
163
  log.info("Checking to see if packages have shared (.so/.dll) libraries...")
219
164
  if detect_and_log_shared_libraries(download_result.downloaded_packages_details):
220
- # TODO: yes/no/ask logic should be removed in 3.0
221
- if not (
222
- allow_shared_libraries
223
- or resolve_allow_shared_libraries_yes_no_ask(
224
- deprecated_allow_native_libraries
225
- )
226
- ):
165
+ if not allow_shared_libraries:
227
166
  raise ClickException(
228
167
  "Some packages contain shared (.so/.dll) libraries. "
229
168
  "Try again with --allow-shared-libraries."
@@ -17,9 +17,10 @@ from __future__ import annotations
17
17
  import logging
18
18
  from pathlib import Path
19
19
 
20
+ from snowflake.cli._plugins.snowpark.package.utils import prepare_app_zip
21
+ from snowflake.cli._plugins.stage.manager import StageManager
22
+ from snowflake.cli.api.identifiers import FQN
20
23
  from snowflake.cli.api.secure_path import SecurePath
21
- from snowflake.cli.plugins.snowpark.package.utils import prepare_app_zip
22
- from snowflake.cli.plugins.stage.manager import StageManager
23
24
 
24
25
  log = logging.getLogger(__name__)
25
26
 
@@ -30,7 +31,7 @@ def upload(file: Path, stage: str, overwrite: bool):
30
31
  temp_app_zip_path = prepare_app_zip(SecurePath(file), temp_dir)
31
32
  sm = StageManager()
32
33
 
33
- sm.create(sm.get_stage_from_path(stage))
34
+ sm.create(FQN.from_string(sm.get_stage_from_path(stage)))
34
35
  put_response = sm.put(
35
36
  temp_app_zip_path.path, stage, overwrite=overwrite
36
37
  ).fetchone()
@@ -25,17 +25,17 @@ from textwrap import dedent
25
25
  from typing import Dict, List, Optional
26
26
 
27
27
  from click import ClickException
28
- from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB
29
- from snowflake.cli.api.secure_path import SecurePath
30
- from snowflake.cli.plugins.snowpark.models import (
28
+ from snowflake.cli._plugins.snowpark.models import (
31
29
  Requirement,
32
30
  RequirementWithFiles,
33
31
  RequirementWithWheel,
34
32
  WheelMetadata,
35
33
  )
36
- from snowflake.cli.plugins.snowpark.package.anaconda_packages import (
34
+ from snowflake.cli._plugins.snowpark.package.anaconda_packages import (
37
35
  AnacondaPackages,
38
36
  )
37
+ from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB
38
+ from snowflake.cli.api.secure_path import SecurePath
39
39
 
40
40
  log = logging.getLogger(__name__)
41
41
 
@@ -61,7 +61,7 @@ def parse_requirements(
61
61
  ).splitlines():
62
62
  line = re.sub(r"\s*#.*", "", line).strip()
63
63
  if line:
64
- reqs.append(Requirement.parse(line))
64
+ reqs.append(Requirement.parse_line(line))
65
65
  return reqs
66
66
 
67
67
 
@@ -12,13 +12,13 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from snowflake.cli._plugins.snowpark import commands
15
16
  from snowflake.cli.api.plugins.command import (
16
17
  SNOWCLI_ROOT_COMMAND_PATH,
17
18
  CommandSpec,
18
19
  CommandType,
19
20
  plugin_hook_impl,
20
21
  )
21
- from snowflake.cli.plugins.nativeapp import commands
22
22
 
23
23
 
24
24
  @plugin_hook_impl
@@ -0,0 +1,109 @@
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
+ from __future__ import annotations
15
+
16
+ from dataclasses import dataclass
17
+ from pathlib import Path, PurePosixPath
18
+
19
+ from snowflake.cli._plugins.snowpark.zipper import zip_dir
20
+ from snowflake.cli.api.console import cli_console
21
+ from snowflake.cli.api.constants import DEPLOYMENT_STAGE
22
+ from snowflake.cli.api.identifiers import FQN
23
+ from snowflake.cli.api.project.schemas.entities.snowpark_entity import PathMapping
24
+ from snowflake.cli.api.secure_path import SecurePath
25
+
26
+
27
+ @dataclass
28
+ class SnowparkProjectPaths:
29
+ """
30
+ This class represents allows you to manage files paths related to given project.
31
+ """
32
+
33
+ project_root: Path
34
+
35
+ def path_relative_to_root(self, artifact_path: Path) -> Path:
36
+ if artifact_path.is_absolute():
37
+ return artifact_path
38
+ return (self.project_root / artifact_path).resolve()
39
+
40
+ def get_artefact_dto(self, artifact_path: PathMapping) -> Artefact:
41
+ return Artefact(
42
+ dest=artifact_path.dest,
43
+ path=self.path_relative_to_root(artifact_path.src),
44
+ )
45
+
46
+ def get_dependencies_artefact(self) -> Artefact:
47
+ return Artefact(dest=None, path=self.dependencies)
48
+
49
+ @property
50
+ def snowflake_requirements(self) -> SecurePath:
51
+ return SecurePath(
52
+ self.path_relative_to_root(Path("requirements.snowflake.txt"))
53
+ )
54
+
55
+ @property
56
+ def requirements(self) -> SecurePath:
57
+ return SecurePath(self.path_relative_to_root(Path("requirements.txt")))
58
+
59
+ @property
60
+ def dependencies(self) -> Path:
61
+ return self.path_relative_to_root(Path("dependencies.zip"))
62
+
63
+
64
+ @dataclass(unsafe_hash=True)
65
+ class Artefact:
66
+ """Helper for getting paths related to given artefact."""
67
+
68
+ path: Path
69
+ dest: str | None = None
70
+
71
+ @property
72
+ def _artefact_name(self) -> str:
73
+ if self.path.is_dir():
74
+ return self.path.stem + ".zip"
75
+ return self.path.name
76
+
77
+ @property
78
+ def post_build_path(self) -> Path:
79
+ """
80
+ Returns post-build artefact path. Directories are mapped to corresponding .zip files.
81
+ """
82
+ return self.path.parent / self._artefact_name
83
+
84
+ def upload_path(self, stage: FQN | str | None) -> str:
85
+ """
86
+ Path on stage to which the artefact should be uploaded.
87
+ """
88
+ stage = stage or DEPLOYMENT_STAGE
89
+ if isinstance(stage, str):
90
+ stage = FQN.from_stage(stage).using_context()
91
+
92
+ stage_path = PurePosixPath(f"@{stage}")
93
+ if self.dest:
94
+ stage_path = stage_path / self.dest
95
+ return str(stage_path) + "/"
96
+
97
+ def import_path(self, stage: FQN | str | None) -> str:
98
+ """Path for UDF/sproc imports clause."""
99
+ return self.upload_path(stage) + self._artefact_name
100
+
101
+ def build(self) -> None:
102
+ """Build the artefact. Applies only to directories. Files are untouched."""
103
+ if not self.path.is_dir():
104
+ return
105
+ cli_console.step(f"Creating: {self.post_build_path.name}")
106
+ zip_dir(
107
+ source=self.path,
108
+ dest_zip=self.post_build_path,
109
+ )
@@ -14,33 +14,7 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- import click
18
17
  import typer
19
- from snowflake.cli.api.commands.flags import (
20
- deprecated_flag_callback,
21
- deprecated_flag_callback_enum,
22
- )
23
- from snowflake.cli.plugins.snowpark.models import YesNoAsk
24
-
25
-
26
- def deprecated_allow_native_libraries_option(old_flag_name: str):
27
- return typer.Option(
28
- YesNoAsk.NO.value,
29
- old_flag_name,
30
- help="Allows native libraries, when using packages installed through PIP",
31
- hidden=True,
32
- callback=deprecated_flag_callback_enum(
33
- f"{old_flag_name} flag is deprecated. Use --allow-shared-libraries flag instead."
34
- ),
35
- )
36
-
37
-
38
- def resolve_allow_shared_libraries_yes_no_ask(allow_shared_libraries: YesNoAsk) -> bool:
39
- if allow_shared_libraries == YesNoAsk.ASK:
40
- return click.confirm("Continue with package installation?", default=False)
41
- else:
42
- return allow_shared_libraries == YesNoAsk.YES
43
-
44
18
 
45
19
  AllowSharedLibrariesOption: bool = typer.Option(
46
20
  False,
@@ -48,16 +22,6 @@ AllowSharedLibrariesOption: bool = typer.Option(
48
22
  help="Allows shared (.so) libraries, when using packages installed through PIP.",
49
23
  )
50
24
 
51
- DeprecatedCheckAnacondaForPyPiDependencies: bool = typer.Option(
52
- True,
53
- "--check-anaconda-for-pypi-deps/--no-check-anaconda-for-pypi-deps",
54
- "-a",
55
- help="""Checks if any of missing Anaconda packages dependencies can be imported directly from Anaconda. Valid values include: `true`, `false`, Default: `true`.""",
56
- hidden=True,
57
- callback=deprecated_flag_callback(
58
- "--check-anaconda-for-pypi-deps flag is deprecated. Use --ignore-anaconda flag instead."
59
- ),
60
- )
61
25
 
62
26
  IgnoreAnacondaOption: bool = typer.Option(
63
27
  False,