snowflake-cli 2.8.2__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 (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 +448 -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 -76
  70. snowflake/cli/{plugins → _plugins}/snowpark/package/manager.py +2 -2
  71. snowflake/cli/{plugins → _plugins}/snowpark/package_utils.py +32 -43
  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 +176 -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-2.8.2.dist-info → snowflake_cli-3.0.2.dist-info}/METADATA +18 -18
  152. snowflake_cli-3.0.2.dist-info/RECORD +242 -0
  153. snowflake_cli-3.0.2.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-2.8.2.dist-info/RECORD +0 -240
  194. snowflake_cli-2.8.2.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-2.8.2.dist-info → snowflake_cli-3.0.2.dist-info}/WHEEL +0 -0
  251. {snowflake_cli-2.8.2.dist-info → snowflake_cli-3.0.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,268 @@
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_entity_model import (
25
+ ProcedureEntityModel,
26
+ SnowparkEntityModel,
27
+ )
28
+ from snowflake.cli._plugins.snowpark.snowpark_project_paths import Artefact
29
+ from snowflake.cli.api.console import cli_console
30
+ from snowflake.cli.api.constants import (
31
+ INIT_TEMPLATE_VARIABLE_CLOSING,
32
+ INIT_TEMPLATE_VARIABLE_OPENING,
33
+ PROJECT_TEMPLATE_VARIABLE_CLOSING,
34
+ PROJECT_TEMPLATE_VARIABLE_OPENING,
35
+ ObjectType,
36
+ )
37
+ from snowflake.cli.api.sql_execution import SqlExecutionMixin
38
+ from snowflake.connector.cursor import SnowflakeCursor
39
+
40
+ log = logging.getLogger(__name__)
41
+
42
+ SnowparkEntities = Dict[str, SnowparkEntityModel]
43
+ StageToArtefactMapping = Dict[str, set[Artefact]]
44
+ EntityToImportPathsMapping = Dict[str, set[str]]
45
+
46
+ DEFAULT_RUNTIME = "3.10"
47
+
48
+
49
+ class SnowparkObject(Enum):
50
+ """This clas is used only for Snowpark execute where choice is limited."""
51
+
52
+ PROCEDURE = str(ObjectType.PROCEDURE)
53
+ FUNCTION = str(ObjectType.FUNCTION)
54
+
55
+
56
+ class SnowparkObjectManager(SqlExecutionMixin):
57
+ def execute(
58
+ self, execution_identifier: str, object_type: SnowparkObject
59
+ ) -> SnowflakeCursor:
60
+ if object_type == SnowparkObject.FUNCTION:
61
+ return self._execute_query(f"select {execution_identifier}")
62
+ if object_type == SnowparkObject.PROCEDURE:
63
+ return self._execute_query(f"call {execution_identifier}")
64
+ raise UsageError(f"Unknown object type: {object_type}.")
65
+
66
+ def create_or_replace(
67
+ self,
68
+ entity: SnowparkEntityModel,
69
+ artifact_files: set[str],
70
+ snowflake_dependencies: list[str],
71
+ ) -> str:
72
+ entity.imports.extend(artifact_files)
73
+ imports = [f"'{x}'" for x in entity.imports]
74
+ packages_list = ",".join(f"'{p}'" for p in snowflake_dependencies)
75
+
76
+ object_type = entity.get_type()
77
+
78
+ query = [
79
+ f"create or replace {object_type} {entity.udf_sproc_identifier.identifier_for_sql}",
80
+ f"copy grants",
81
+ f"returns {entity.returns}",
82
+ "language python",
83
+ f"runtime_version={entity.runtime or DEFAULT_RUNTIME}",
84
+ f"imports=({', '.join(imports)})",
85
+ f"handler='{entity.handler}'",
86
+ f"packages=({packages_list})",
87
+ ]
88
+
89
+ if entity.external_access_integrations:
90
+ query.append(entity.get_external_access_integrations_sql())
91
+
92
+ if entity.secrets:
93
+ query.append(entity.get_secrets_sql())
94
+
95
+ if isinstance(entity, ProcedureEntityModel) and entity.execute_as_caller:
96
+ query.append("execute as caller")
97
+
98
+ return self._execute_query("\n".join(query))
99
+
100
+ def deploy_entity(
101
+ self,
102
+ entity: SnowparkEntityModel,
103
+ existing_objects: Dict[str, SnowflakeCursor],
104
+ snowflake_dependencies: List[str],
105
+ entities_to_artifact_map: EntityToImportPathsMapping,
106
+ ):
107
+ cli_console.step(f"Creating {entity.type} {entity.fqn}")
108
+ object_exists = entity.entity_id in existing_objects
109
+ replace_object = False
110
+ if object_exists:
111
+ replace_object = _check_if_replace_is_required(
112
+ entity=entity,
113
+ current_state=existing_objects[entity.entity_id],
114
+ snowflake_dependencies=snowflake_dependencies,
115
+ stage_artifact_files=entities_to_artifact_map[entity.entity_id],
116
+ )
117
+
118
+ state = {
119
+ "object": entity.udf_sproc_identifier.identifier_with_arg_names_types_defaults,
120
+ "type": entity.get_type(),
121
+ }
122
+ if object_exists and not replace_object:
123
+ return {**state, "status": "packages updated"}
124
+
125
+ self.create_or_replace(
126
+ entity=entity,
127
+ artifact_files=entities_to_artifact_map[entity.entity_id],
128
+ snowflake_dependencies=snowflake_dependencies,
129
+ )
130
+ return {
131
+ **state,
132
+ "status": "created" if not object_exists else "definition updated",
133
+ }
134
+
135
+
136
+ def _check_if_replace_is_required(
137
+ entity: SnowparkEntityModel,
138
+ current_state,
139
+ snowflake_dependencies: List[str],
140
+ stage_artifact_files: set[str],
141
+ ) -> bool:
142
+ object_type = entity.get_type()
143
+ resource_json = _convert_resource_details_to_dict(current_state)
144
+ old_dependencies = resource_json["packages"]
145
+
146
+ if _snowflake_dependencies_differ(old_dependencies, snowflake_dependencies):
147
+ log.info(
148
+ "Found difference of package requirements. Replacing the %s.", object_type
149
+ )
150
+ return True
151
+
152
+ if set(entity.external_access_integrations) != set(
153
+ resource_json.get("external_access_integrations", [])
154
+ ):
155
+ log.info(
156
+ "Found difference of external access integrations. Replacing the %s.",
157
+ object_type,
158
+ )
159
+ return True
160
+
161
+ if (
162
+ resource_json["handler"].lower() != entity.handler.lower()
163
+ or _sql_to_python_return_type_mapper(resource_json["returns"]).lower()
164
+ != entity.returns.lower()
165
+ ):
166
+ log.info(
167
+ "Return type or handler types do not match. Replacing the %s.", object_type
168
+ )
169
+ return True
170
+
171
+ if _compare_imports(resource_json, entity.imports, stage_artifact_files):
172
+ log.info("Imports do not match. Replacing the %s", object_type)
173
+ return True
174
+
175
+ if entity.runtime is not None and entity.runtime != resource_json.get(
176
+ "runtime_version", "RUNTIME_NOT_SET"
177
+ ):
178
+ log.info("Runtime versions do not match. Replacing the %s", object_type)
179
+ return True
180
+
181
+ if isinstance(entity, ProcedureEntityModel):
182
+ if resource_json.get("execute as", "OWNER") != (
183
+ "CALLER" if entity.execute_as_caller else "OWNER"
184
+ ):
185
+ log.info(
186
+ "Execute as caller settings do not match. Replacing the %s", object_type
187
+ )
188
+ return True
189
+
190
+ return False
191
+
192
+
193
+ def _convert_resource_details_to_dict(function_details: SnowflakeCursor) -> dict:
194
+ import json
195
+
196
+ function_dict = {}
197
+ json_properties = ["packages", "installed_packages"]
198
+ for function in function_details:
199
+ if function[0] in json_properties:
200
+ function_dict[function[0]] = json.loads(
201
+ function[1].replace("'", '"'),
202
+ )
203
+ else:
204
+ function_dict[function[0]] = function[1]
205
+ return function_dict
206
+
207
+
208
+ def _snowflake_dependencies_differ(
209
+ old_dependencies: List[str], new_dependencies: List[str]
210
+ ) -> bool:
211
+ def _standardize(packages: List[str]) -> Set[str]:
212
+ return set(
213
+ Requirement.parse_line(package).name_and_version for package in packages
214
+ )
215
+
216
+ return _standardize(old_dependencies) != _standardize(new_dependencies)
217
+
218
+
219
+ def _sql_to_python_return_type_mapper(resource_return_type: str) -> str:
220
+ """
221
+ Some of the Python data types get converted to SQL types, when function/procedure is created.
222
+ So, to properly compare types, we use mapping based on:
223
+ https://docs.snowflake.com/en/developer-guide/udf-stored-procedure-data-type-mapping#sql-python-data-type-mappings
224
+
225
+ Mind you, this only applies to cases, in which Snowflake accepts Python type as return.
226
+ Ie. if function returns list, it has to be declared as 'array' during creation,
227
+ therefore any conversion is not necessary
228
+ """
229
+ mapping = {
230
+ "number(38,0)": "int",
231
+ "timestamp_ntz(9)": "datetime",
232
+ "timestamp_tz(9)": "datetime",
233
+ "varchar(16777216)": "string",
234
+ }
235
+
236
+ return mapping.get(resource_return_type.lower(), resource_return_type.lower())
237
+
238
+
239
+ def _compare_imports(
240
+ resource_json: dict, imports: List[str], artifact_files: set[str]
241
+ ) -> bool:
242
+ pattern = re.compile(r"(?:\[@?\w+_\w+\.)?(\w+(?:/\w+)+\.\w+)(?:\])?")
243
+
244
+ project_imports = {
245
+ imp
246
+ for import_string in [*imports, *artifact_files]
247
+ for imp in pattern.findall(import_string.lower())
248
+ }
249
+
250
+ if "imports" not in resource_json.keys():
251
+ object_imports = set()
252
+ else:
253
+ object_imports = {
254
+ imp.lower()
255
+ for imp in pattern.findall(resource_json.get("imports", "").lower())
256
+ }
257
+
258
+ return project_imports != object_imports
259
+
260
+
261
+ def is_name_a_templated_one(name: str) -> bool:
262
+ return (
263
+ PROJECT_TEMPLATE_VARIABLE_OPENING in name
264
+ and PROJECT_TEMPLATE_VARIABLE_CLOSING in name
265
+ ) or (
266
+ INIT_TEMPLATE_VARIABLE_OPENING in name
267
+ and INIT_TEMPLATE_VARIABLE_CLOSING in name
268
+ )
@@ -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
 
@@ -18,16 +18,13 @@ import logging
18
18
  from dataclasses import dataclass
19
19
  from typing import Dict, List, Set
20
20
 
21
- import requests
22
- from click import ClickException
23
21
  from packaging.requirements import InvalidRequirement
24
22
  from packaging.requirements import Requirement as PkgRequirement
25
23
  from packaging.version import InvalidVersion, parse
26
- from requests import HTTPError
24
+ from snowflake.cli._plugins.snowpark.models import Requirement
27
25
  from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
28
26
  from snowflake.cli.api.secure_path import SecurePath
29
27
  from snowflake.cli.api.sql_execution import SqlExecutionMixin
30
- from snowflake.cli.plugins.snowpark.models import Requirement
31
28
  from snowflake.connector import DictCursor
32
29
 
33
30
  log = logging.getLogger(__name__)
@@ -170,23 +167,13 @@ class AnacondaPackagesManager(SqlExecutionMixin):
170
167
  "https://repo.anaconda.com/pkgs/snowflake/channeldata.json"
171
168
  )
172
169
 
173
- # TODO in v3.0: Keep only SQL query, remove fallback to JSON with channel's metadata
174
170
  def find_packages_available_in_snowflake_anaconda(self) -> AnacondaPackages:
175
171
  """
176
172
  Finds python packages available in Snowflake to use in functions and stored procedures.
177
173
  It tries to get the list of packages using SQL query
178
174
  but if the try fails then the fallback is to parse JSON containing info about Snowflake's Anaconda channel.
179
175
  """
180
- try:
181
- packages = self._query_snowflake_for_available_packages()
182
- except Exception as ex:
183
- log.warning(
184
- "Cannot fetch available packages information from Snowflake. "
185
- "Please check your connection configuration. "
186
- "Fallback to Anaconda channel metadata."
187
- )
188
- log.debug("Available packages query failure: %s", ex.__str__(), exc_info=ex)
189
- packages = self._get_available_packages_from_anaconda_channel_info()
176
+ packages = self._query_snowflake_for_available_packages()
190
177
  return AnacondaPackages(packages)
191
178
 
192
179
  def _query_snowflake_for_available_packages(self) -> dict[str, AvailablePackage]:
@@ -210,24 +197,3 @@ class AnacondaPackagesManager(SqlExecutionMixin):
210
197
  snowflake_name=package_name, versions={version}
211
198
  )
212
199
  return packages
213
-
214
- def _get_available_packages_from_anaconda_channel_info(
215
- self,
216
- ) -> dict[str, AvailablePackage]:
217
- try:
218
- response = requests.get(self._snowflake_channel_url)
219
- response.raise_for_status()
220
- packages = {}
221
- for key, package in response.json()["packages"].items():
222
- if not (version := package.get("version")):
223
- continue
224
- package_name = package.get("name", key)
225
- standardized_name = Requirement.standardize_name(package_name)
226
- packages[standardized_name] = AvailablePackage(
227
- snowflake_name=package_name, versions={version}
228
- )
229
- return packages
230
- except HTTPError as err:
231
- raise ClickException(
232
- f"Accessing Snowflake Anaconda channel failed. Reason {err}"
233
- )
@@ -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
  """
@@ -202,8 +147,6 @@ def package_create(
202
147
  skip_version_check=skip_version_check,
203
148
  pip_index_url=index_url,
204
149
  )
205
- if not download_result.succeeded:
206
- raise ClickException(download_result.error_message)
207
150
 
208
151
  # check if package was detected as available
209
152
  package_available_in_conda = any(
@@ -217,13 +160,7 @@ def package_create(
217
160
  # The package is not in anaconda, so we have to pack it
218
161
  log.info("Checking to see if packages have shared (.so/.dll) libraries...")
219
162
  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
- ):
163
+ if not allow_shared_libraries:
227
164
  raise ClickException(
228
165
  "Some packages contain shared (.so/.dll) libraries. "
229
166
  "Try again with --allow-shared-libraries."
@@ -17,10 +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
20
22
  from snowflake.cli.api.identifiers import FQN
21
23
  from snowflake.cli.api.secure_path import SecurePath
22
- from snowflake.cli.plugins.snowpark.package.utils import prepare_app_zip
23
- from snowflake.cli.plugins.stage.manager import StageManager
24
24
 
25
25
  log = logging.getLogger(__name__)
26
26
 
@@ -21,21 +21,20 @@ import os
21
21
  import re
22
22
  import subprocess
23
23
  from pathlib import Path
24
- from textwrap import dedent
25
24
  from typing import Dict, List, Optional
26
25
 
27
26
  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 (
27
+ from snowflake.cli._plugins.snowpark.models import (
31
28
  Requirement,
32
29
  RequirementWithFiles,
33
30
  RequirementWithWheel,
34
31
  WheelMetadata,
35
32
  )
36
- from snowflake.cli.plugins.snowpark.package.anaconda_packages import (
33
+ from snowflake.cli._plugins.snowpark.package.anaconda_packages import (
37
34
  AnacondaPackages,
38
35
  )
36
+ from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB
37
+ from snowflake.cli.api.secure_path import SecurePath
39
38
 
40
39
  log = logging.getLogger(__name__)
41
40
 
@@ -61,7 +60,7 @@ def parse_requirements(
61
60
  ).splitlines():
62
61
  line = re.sub(r"\s*#.*", "", line).strip()
63
62
  if line:
64
- reqs.append(Requirement.parse(line))
63
+ reqs.append(Requirement.parse_line(line))
65
64
  return reqs
66
65
 
67
66
 
@@ -97,6 +96,7 @@ def get_package_name_from_pip_wheel(package: str, index_url: str | None = None)
97
96
  download_dir=tmp_dir.path,
98
97
  index_url=index_url,
99
98
  dependencies=False,
99
+ raise_on_error=False,
100
100
  )
101
101
  file_list = [
102
102
  f.path.name for f in tmp_dir.iterdir() if f.path.name.endswith(".whl")
@@ -117,7 +117,6 @@ def _write_requirements_file(file_path: SecurePath, requirements: List[Requireme
117
117
 
118
118
  @dataclasses.dataclass
119
119
  class DownloadUnavailablePackagesResult:
120
- succeeded: bool
121
120
  error_message: str | None = None
122
121
  anaconda_packages: List[Requirement] = dataclasses.field(default_factory=list)
123
122
  downloaded_packages_details: List[RequirementWithFiles] = dataclasses.field(
@@ -151,8 +150,7 @@ def download_unavailable_packages(
151
150
  if not requirements:
152
151
  # all packages are available in Snowflake
153
152
  return DownloadUnavailablePackagesResult(
154
- succeeded=True,
155
- anaconda_packages=packages_in_snowflake,
153
+ anaconda_packages=packages_in_snowflake
156
154
  )
157
155
 
158
156
  # download all packages with their dependencies
@@ -160,19 +158,14 @@ def download_unavailable_packages(
160
158
  # This is a Windows workaround where use TemporaryDirectory instead of NamedTemporaryFile
161
159
  requirements_file = downloads_dir / "requirements.txt"
162
160
  _write_requirements_file(requirements_file, requirements) # type: ignore
163
- pip_wheel_result = pip_wheel(
161
+ pip_wheel(
164
162
  package_name=None,
165
163
  requirements_file=requirements_file.path, # type: ignore
166
164
  download_dir=downloads_dir.path,
167
165
  index_url=pip_index_url,
168
166
  dependencies=True,
167
+ raise_on_error=True,
169
168
  )
170
- if pip_wheel_result != 0:
171
- log.info(_pip_failed_log_msg(pip_wheel_result))
172
- return DownloadUnavailablePackagesResult(
173
- succeeded=False,
174
- error_message=_pip_failed_log_msg(pip_wheel_result),
175
- )
176
169
 
177
170
  # scan all downloaded packages and filter out ones available on Anaconda
178
171
  dependencies = split_downloaded_dependencies(
@@ -196,7 +189,6 @@ def download_unavailable_packages(
196
189
  for package in dependencies.unavailable_dependencies_wheels:
197
190
  package.extract_files(target_dir.path)
198
191
  return DownloadUnavailablePackagesResult(
199
- succeeded=True,
200
192
  anaconda_packages=packages_in_snowflake,
201
193
  downloaded_packages_details=[
202
194
  RequirementWithFiles(requirement=dep.requirement, files=dep.namelist())
@@ -211,7 +203,8 @@ def pip_wheel(
211
203
  download_dir: Path,
212
204
  index_url: Optional[str],
213
205
  dependencies: bool = True,
214
- ):
206
+ raise_on_error: bool = True,
207
+ ) -> int:
215
208
  command = ["-m", "pip", "wheel", "-w", str(download_dir)]
216
209
  if package_name:
217
210
  command.append(package_name)
@@ -222,23 +215,30 @@ def pip_wheel(
222
215
  if not dependencies:
223
216
  command.append("--no-deps")
224
217
 
225
- try:
218
+ log.info(
219
+ "Running pip wheel with command: %s",
220
+ " ".join([str(com) for com in command]),
221
+ )
222
+ result = subprocess.run(
223
+ ["python", *command],
224
+ capture_output=True,
225
+ text=True,
226
+ encoding=locale.getpreferredencoding(),
227
+ )
228
+ if result.returncode != 0:
226
229
  log.info(
227
- "Running pip wheel with command: %s",
228
- " ".join([str(com) for com in command]),
229
- )
230
- process = subprocess.run(
231
- ["python", *command],
232
- capture_output=True,
233
- text=True,
234
- encoding=locale.getpreferredencoding(),
230
+ "pip wheel finished with error code %d. Details: %s",
231
+ result.returncode,
232
+ result.stdout + result.stderr,
235
233
  )
236
- except subprocess.CalledProcessError as e:
237
- log.error("Encountered error %s", e.stderr)
238
- raise ClickException(f"Encountered error while running pip wheel.")
234
+ if raise_on_error:
235
+ raise ClickException(
236
+ f"pip wheel finished with error code {result.returncode}. Please re-run with --verbose or --debug for more details."
237
+ )
238
+ else:
239
+ log.info("pip wheel command executed successfully")
239
240
 
240
- log.info("Pip wheel command executed successfully")
241
- return process.returncode
241
+ return result.returncode
242
242
 
243
243
 
244
244
  @dataclasses.dataclass
@@ -341,14 +341,3 @@ def _log_dependencies_found_in_conda(available_dependencies: List[Requirement])
341
341
  )
342
342
  else:
343
343
  log.info("None of the package dependencies were found on Anaconda")
344
-
345
-
346
- def _pip_failed_log_msg(return_code: int) -> str:
347
- return dedent(
348
- f"""
349
- pip failed with return code {return_code}. Most likely reasons:
350
- * incorrect package name or version
351
- * package isn't compatible with host architecture (most probably due to .so libraries)
352
- * pip is not installed correctly
353
- """
354
- )