snowflake-cli-labs 2.8.0rc1__py3-none-any.whl → 2.8.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 (242) hide show
  1. README.md +21 -0
  2. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-2.8.2.dist-info}/METADATA +7 -95
  3. snowflake_cli_labs-2.8.2.dist-info/RECORD +5 -0
  4. snowflake/cli/__about__.py +0 -17
  5. snowflake/cli/__init__.py +0 -13
  6. snowflake/cli/api/__init__.py +0 -48
  7. snowflake/cli/api/cli_global_context.py +0 -390
  8. snowflake/cli/api/commands/__init__.py +0 -13
  9. snowflake/cli/api/commands/alias.py +0 -23
  10. snowflake/cli/api/commands/decorators.py +0 -354
  11. snowflake/cli/api/commands/execution_metadata.py +0 -40
  12. snowflake/cli/api/commands/experimental_behaviour.py +0 -19
  13. snowflake/cli/api/commands/flags.py +0 -640
  14. snowflake/cli/api/commands/project_initialisation.py +0 -65
  15. snowflake/cli/api/commands/snow_typer.py +0 -237
  16. snowflake/cli/api/commands/typer_pre_execute.py +0 -26
  17. snowflake/cli/api/config.py +0 -348
  18. snowflake/cli/api/console/__init__.py +0 -17
  19. snowflake/cli/api/console/abc.py +0 -89
  20. snowflake/cli/api/console/console.py +0 -134
  21. snowflake/cli/api/console/enum.py +0 -17
  22. snowflake/cli/api/constants.py +0 -79
  23. snowflake/cli/api/errno.py +0 -27
  24. snowflake/cli/api/exceptions.py +0 -164
  25. snowflake/cli/api/feature_flags.py +0 -55
  26. snowflake/cli/api/identifiers.py +0 -154
  27. snowflake/cli/api/output/__init__.py +0 -13
  28. snowflake/cli/api/output/formats.py +0 -20
  29. snowflake/cli/api/output/types.py +0 -118
  30. snowflake/cli/api/plugins/__init__.py +0 -13
  31. snowflake/cli/api/plugins/command/__init__.py +0 -72
  32. snowflake/cli/api/plugins/command/plugin_hook_specs.py +0 -21
  33. snowflake/cli/api/plugins/plugin_config.py +0 -32
  34. snowflake/cli/api/project/__init__.py +0 -13
  35. snowflake/cli/api/project/definition.py +0 -84
  36. snowflake/cli/api/project/definition_manager.py +0 -134
  37. snowflake/cli/api/project/errors.py +0 -56
  38. snowflake/cli/api/project/project_verification.py +0 -23
  39. snowflake/cli/api/project/schemas/__init__.py +0 -13
  40. snowflake/cli/api/project/schemas/entities/application_entity.py +0 -44
  41. snowflake/cli/api/project/schemas/entities/application_package_entity.py +0 -66
  42. snowflake/cli/api/project/schemas/entities/common.py +0 -78
  43. snowflake/cli/api/project/schemas/entities/entities.py +0 -30
  44. snowflake/cli/api/project/schemas/identifier_model.py +0 -49
  45. snowflake/cli/api/project/schemas/native_app/__init__.py +0 -13
  46. snowflake/cli/api/project/schemas/native_app/application.py +0 -62
  47. snowflake/cli/api/project/schemas/native_app/native_app.py +0 -93
  48. snowflake/cli/api/project/schemas/native_app/package.py +0 -78
  49. snowflake/cli/api/project/schemas/native_app/path_mapping.py +0 -65
  50. snowflake/cli/api/project/schemas/project_definition.py +0 -199
  51. snowflake/cli/api/project/schemas/snowpark/__init__.py +0 -13
  52. snowflake/cli/api/project/schemas/snowpark/argument.py +0 -28
  53. snowflake/cli/api/project/schemas/snowpark/callable.py +0 -69
  54. snowflake/cli/api/project/schemas/snowpark/snowpark.py +0 -36
  55. snowflake/cli/api/project/schemas/streamlit/__init__.py +0 -13
  56. snowflake/cli/api/project/schemas/streamlit/streamlit.py +0 -46
  57. snowflake/cli/api/project/schemas/template.py +0 -77
  58. snowflake/cli/api/project/schemas/updatable_model.py +0 -194
  59. snowflake/cli/api/project/util.py +0 -261
  60. snowflake/cli/api/rendering/__init__.py +0 -13
  61. snowflake/cli/api/rendering/jinja.py +0 -112
  62. snowflake/cli/api/rendering/project_definition_templates.py +0 -39
  63. snowflake/cli/api/rendering/project_templates.py +0 -98
  64. snowflake/cli/api/rendering/sql_templates.py +0 -60
  65. snowflake/cli/api/rest_api.py +0 -172
  66. snowflake/cli/api/sanitizers.py +0 -43
  67. snowflake/cli/api/secure_path.py +0 -362
  68. snowflake/cli/api/secure_utils.py +0 -29
  69. snowflake/cli/api/sql_execution.py +0 -260
  70. snowflake/cli/api/utils/__init__.py +0 -13
  71. snowflake/cli/api/utils/cursor.py +0 -34
  72. snowflake/cli/api/utils/definition_rendering.py +0 -383
  73. snowflake/cli/api/utils/dict_utils.py +0 -73
  74. snowflake/cli/api/utils/error_handling.py +0 -23
  75. snowflake/cli/api/utils/graph.py +0 -97
  76. snowflake/cli/api/utils/models.py +0 -63
  77. snowflake/cli/api/utils/naming_utils.py +0 -13
  78. snowflake/cli/api/utils/path_utils.py +0 -36
  79. snowflake/cli/api/utils/templating_functions.py +0 -144
  80. snowflake/cli/api/utils/types.py +0 -35
  81. snowflake/cli/app/__init__.py +0 -22
  82. snowflake/cli/app/__main__.py +0 -31
  83. snowflake/cli/app/api_impl/__init__.py +0 -13
  84. snowflake/cli/app/api_impl/plugin/__init__.py +0 -13
  85. snowflake/cli/app/api_impl/plugin/plugin_config_provider_impl.py +0 -66
  86. snowflake/cli/app/build_and_push.sh +0 -8
  87. snowflake/cli/app/cli_app.py +0 -243
  88. snowflake/cli/app/commands_registration/__init__.py +0 -33
  89. snowflake/cli/app/commands_registration/builtin_plugins.py +0 -54
  90. snowflake/cli/app/commands_registration/command_plugins_loader.py +0 -169
  91. snowflake/cli/app/commands_registration/commands_registration_with_callbacks.py +0 -105
  92. snowflake/cli/app/commands_registration/exception_logging.py +0 -26
  93. snowflake/cli/app/commands_registration/threadsafe.py +0 -48
  94. snowflake/cli/app/commands_registration/typer_registration.py +0 -153
  95. snowflake/cli/app/constants.py +0 -19
  96. snowflake/cli/app/dev/__init__.py +0 -13
  97. snowflake/cli/app/dev/commands_structure.py +0 -48
  98. snowflake/cli/app/dev/docs/__init__.py +0 -13
  99. snowflake/cli/app/dev/docs/commands_docs_generator.py +0 -100
  100. snowflake/cli/app/dev/docs/generator.py +0 -35
  101. snowflake/cli/app/dev/docs/project_definition_docs_generator.py +0 -58
  102. snowflake/cli/app/dev/docs/project_definition_generate_json_schema.py +0 -227
  103. snowflake/cli/app/dev/docs/template_utils.py +0 -23
  104. snowflake/cli/app/dev/docs/templates/definition_description.rst.jinja2 +0 -38
  105. snowflake/cli/app/dev/docs/templates/overview.rst.jinja2 +0 -9
  106. snowflake/cli/app/dev/docs/templates/usage.rst.jinja2 +0 -57
  107. snowflake/cli/app/dev/pycharm_remote_debug.py +0 -46
  108. snowflake/cli/app/loggers.py +0 -199
  109. snowflake/cli/app/main_typer.py +0 -62
  110. snowflake/cli/app/printing.py +0 -181
  111. snowflake/cli/app/snow_connector.py +0 -243
  112. snowflake/cli/app/telemetry.py +0 -189
  113. snowflake/cli/plugins/__init__.py +0 -13
  114. snowflake/cli/plugins/connection/__init__.py +0 -13
  115. snowflake/cli/plugins/connection/commands.py +0 -330
  116. snowflake/cli/plugins/connection/plugin_spec.py +0 -30
  117. snowflake/cli/plugins/connection/util.py +0 -179
  118. snowflake/cli/plugins/cortex/__init__.py +0 -13
  119. snowflake/cli/plugins/cortex/commands.py +0 -327
  120. snowflake/cli/plugins/cortex/constants.py +0 -17
  121. snowflake/cli/plugins/cortex/manager.py +0 -189
  122. snowflake/cli/plugins/cortex/plugin_spec.py +0 -30
  123. snowflake/cli/plugins/cortex/types.py +0 -22
  124. snowflake/cli/plugins/git/__init__.py +0 -13
  125. snowflake/cli/plugins/git/commands.py +0 -305
  126. snowflake/cli/plugins/git/manager.py +0 -96
  127. snowflake/cli/plugins/git/plugin_spec.py +0 -30
  128. snowflake/cli/plugins/init/__init__.py +0 -13
  129. snowflake/cli/plugins/init/commands.py +0 -244
  130. snowflake/cli/plugins/init/plugin_spec.py +0 -30
  131. snowflake/cli/plugins/nativeapp/__init__.py +0 -13
  132. snowflake/cli/plugins/nativeapp/artifacts.py +0 -742
  133. snowflake/cli/plugins/nativeapp/codegen/__init__.py +0 -13
  134. snowflake/cli/plugins/nativeapp/codegen/artifact_processor.py +0 -91
  135. snowflake/cli/plugins/nativeapp/codegen/compiler.py +0 -130
  136. snowflake/cli/plugins/nativeapp/codegen/sandbox.py +0 -306
  137. snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -172
  138. snowflake/cli/plugins/nativeapp/codegen/setup/setup_driver.py.source +0 -56
  139. snowflake/cli/plugins/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -181
  140. snowflake/cli/plugins/nativeapp/codegen/snowpark/extension_function_utils.py +0 -217
  141. snowflake/cli/plugins/nativeapp/codegen/snowpark/models.py +0 -61
  142. snowflake/cli/plugins/nativeapp/codegen/snowpark/python_processor.py +0 -528
  143. snowflake/cli/plugins/nativeapp/commands.py +0 -439
  144. snowflake/cli/plugins/nativeapp/common_flags.py +0 -44
  145. snowflake/cli/plugins/nativeapp/constants.py +0 -27
  146. snowflake/cli/plugins/nativeapp/exceptions.py +0 -122
  147. snowflake/cli/plugins/nativeapp/feature_flags.py +0 -24
  148. snowflake/cli/plugins/nativeapp/init.py +0 -345
  149. snowflake/cli/plugins/nativeapp/manager.py +0 -823
  150. snowflake/cli/plugins/nativeapp/plugin_spec.py +0 -30
  151. snowflake/cli/plugins/nativeapp/policy.py +0 -50
  152. snowflake/cli/plugins/nativeapp/project_model.py +0 -195
  153. snowflake/cli/plugins/nativeapp/run_processor.py +0 -389
  154. snowflake/cli/plugins/nativeapp/teardown_processor.py +0 -301
  155. snowflake/cli/plugins/nativeapp/utils.py +0 -98
  156. snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +0 -135
  157. snowflake/cli/plugins/nativeapp/version/__init__.py +0 -13
  158. snowflake/cli/plugins/nativeapp/version/commands.py +0 -170
  159. snowflake/cli/plugins/nativeapp/version/version_processor.py +0 -362
  160. snowflake/cli/plugins/notebook/__init__.py +0 -13
  161. snowflake/cli/plugins/notebook/commands.py +0 -84
  162. snowflake/cli/plugins/notebook/exceptions.py +0 -20
  163. snowflake/cli/plugins/notebook/manager.py +0 -71
  164. snowflake/cli/plugins/notebook/plugin_spec.py +0 -30
  165. snowflake/cli/plugins/notebook/types.py +0 -16
  166. snowflake/cli/plugins/object/__init__.py +0 -13
  167. snowflake/cli/plugins/object/command_aliases.py +0 -94
  168. snowflake/cli/plugins/object/commands.py +0 -174
  169. snowflake/cli/plugins/object/common.py +0 -85
  170. snowflake/cli/plugins/object/manager.py +0 -96
  171. snowflake/cli/plugins/object/plugin_spec.py +0 -30
  172. snowflake/cli/plugins/object_stage_deprecated/__init__.py +0 -15
  173. snowflake/cli/plugins/object_stage_deprecated/commands.py +0 -122
  174. snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +0 -32
  175. snowflake/cli/plugins/snowpark/__init__.py +0 -13
  176. snowflake/cli/plugins/snowpark/commands.py +0 -548
  177. snowflake/cli/plugins/snowpark/common.py +0 -307
  178. snowflake/cli/plugins/snowpark/manager.py +0 -109
  179. snowflake/cli/plugins/snowpark/models.py +0 -156
  180. snowflake/cli/plugins/snowpark/package/__init__.py +0 -13
  181. snowflake/cli/plugins/snowpark/package/anaconda_packages.py +0 -233
  182. snowflake/cli/plugins/snowpark/package/commands.py +0 -256
  183. snowflake/cli/plugins/snowpark/package/manager.py +0 -43
  184. snowflake/cli/plugins/snowpark/package/utils.py +0 -26
  185. snowflake/cli/plugins/snowpark/package_utils.py +0 -354
  186. snowflake/cli/plugins/snowpark/plugin_spec.py +0 -30
  187. snowflake/cli/plugins/snowpark/snowpark_package_paths.py +0 -65
  188. snowflake/cli/plugins/snowpark/snowpark_shared.py +0 -95
  189. snowflake/cli/plugins/snowpark/zipper.py +0 -81
  190. snowflake/cli/plugins/spcs/__init__.py +0 -35
  191. snowflake/cli/plugins/spcs/common.py +0 -99
  192. snowflake/cli/plugins/spcs/compute_pool/__init__.py +0 -13
  193. snowflake/cli/plugins/spcs/compute_pool/commands.py +0 -240
  194. snowflake/cli/plugins/spcs/compute_pool/manager.py +0 -121
  195. snowflake/cli/plugins/spcs/image_registry/__init__.py +0 -13
  196. snowflake/cli/plugins/spcs/image_registry/commands.py +0 -65
  197. snowflake/cli/plugins/spcs/image_registry/manager.py +0 -105
  198. snowflake/cli/plugins/spcs/image_repository/__init__.py +0 -13
  199. snowflake/cli/plugins/spcs/image_repository/commands.py +0 -196
  200. snowflake/cli/plugins/spcs/image_repository/manager.py +0 -84
  201. snowflake/cli/plugins/spcs/jobs/__init__.py +0 -13
  202. snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
  203. snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
  204. snowflake/cli/plugins/spcs/plugin_spec.py +0 -30
  205. snowflake/cli/plugins/spcs/services/__init__.py +0 -13
  206. snowflake/cli/plugins/spcs/services/commands.py +0 -311
  207. snowflake/cli/plugins/spcs/services/manager.py +0 -170
  208. snowflake/cli/plugins/sql/__init__.py +0 -13
  209. snowflake/cli/plugins/sql/commands.py +0 -83
  210. snowflake/cli/plugins/sql/manager.py +0 -92
  211. snowflake/cli/plugins/sql/plugin_spec.py +0 -30
  212. snowflake/cli/plugins/sql/snowsql_templating.py +0 -28
  213. snowflake/cli/plugins/stage/__init__.py +0 -13
  214. snowflake/cli/plugins/stage/commands.py +0 -261
  215. snowflake/cli/plugins/stage/diff.py +0 -326
  216. snowflake/cli/plugins/stage/manager.py +0 -544
  217. snowflake/cli/plugins/stage/md5.py +0 -160
  218. snowflake/cli/plugins/stage/plugin_spec.py +0 -30
  219. snowflake/cli/plugins/streamlit/__init__.py +0 -13
  220. snowflake/cli/plugins/streamlit/commands.py +0 -186
  221. snowflake/cli/plugins/streamlit/manager.py +0 -222
  222. snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
  223. snowflake/cli/plugins/workspace/__init__.py +0 -13
  224. snowflake/cli/plugins/workspace/commands.py +0 -35
  225. snowflake/cli/plugins/workspace/plugin_spec.py +0 -30
  226. snowflake/cli/templates/default_snowpark/.gitignore +0 -4
  227. snowflake/cli/templates/default_snowpark/app/__init__.py +0 -0
  228. snowflake/cli/templates/default_snowpark/app/common.py +0 -2
  229. snowflake/cli/templates/default_snowpark/app/functions.py +0 -15
  230. snowflake/cli/templates/default_snowpark/app/procedures.py +0 -22
  231. snowflake/cli/templates/default_snowpark/requirements.txt +0 -1
  232. snowflake/cli/templates/default_snowpark/snowflake.yml +0 -23
  233. snowflake/cli/templates/default_streamlit/.gitignore +0 -4
  234. snowflake/cli/templates/default_streamlit/common/hello.py +0 -2
  235. snowflake/cli/templates/default_streamlit/environment.yml +0 -6
  236. snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -3
  237. snowflake/cli/templates/default_streamlit/snowflake.yml +0 -10
  238. snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -4
  239. snowflake_cli_labs-2.8.0rc1.dist-info/RECORD +0 -240
  240. snowflake_cli_labs-2.8.0rc1.dist-info/entry_points.txt +0 -2
  241. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-2.8.2.dist-info}/WHEEL +0 -0
  242. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-2.8.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,233 +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 logging
18
- from dataclasses import dataclass
19
- from typing import Dict, List, Set
20
-
21
- import requests
22
- from click import ClickException
23
- from packaging.requirements import InvalidRequirement
24
- from packaging.requirements import Requirement as PkgRequirement
25
- from packaging.version import InvalidVersion, parse
26
- from requests import HTTPError
27
- from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
28
- from snowflake.cli.api.secure_path import SecurePath
29
- from snowflake.cli.api.sql_execution import SqlExecutionMixin
30
- from snowflake.cli.plugins.snowpark.models import Requirement
31
- from snowflake.connector import DictCursor
32
-
33
- log = logging.getLogger(__name__)
34
-
35
-
36
- @dataclass
37
- class FilterRequirementsResult:
38
- """A dataclass to hold the results of parsing requirements files and dividing them into
39
- snowflake-supported vs other packages.
40
- """
41
-
42
- in_snowflake: List[Requirement]
43
- unavailable: List[Requirement]
44
-
45
-
46
- @dataclass
47
- class AvailablePackage:
48
- snowflake_name: str
49
- versions: Set[str]
50
-
51
- def iter_versions(self):
52
- for version in self.versions:
53
- yield parse(version)
54
-
55
- def is_required_version_available(self, requirement: Requirement) -> bool:
56
- try:
57
- package_specifiers = PkgRequirement(requirement.line).specifier
58
- return any(
59
- version in package_specifiers for version in self.iter_versions()
60
- )
61
- except (InvalidVersion, InvalidRequirement):
62
- # fail-safe for non-pep508 formats
63
- return False
64
-
65
-
66
- class AnacondaPackages:
67
- def __init__(self, packages: Dict[str, AvailablePackage]):
68
- """
69
- [packages] should be a dictionary mapping package name to AnacondaPackageData object.
70
- All package names should be provided in wheel escape format:
71
- https://peps.python.org/pep-0491/#escaping-and-unicode
72
- """
73
- self._packages = packages
74
-
75
- @classmethod
76
- def empty(cls):
77
- return cls({})
78
-
79
- def is_package_available(
80
- self, package: Requirement, skip_version_check: bool = False
81
- ) -> bool:
82
- """
83
- Checks of a requirement is available in the Snowflake Anaconda Channel.
84
-
85
- As Snowflake currently doesn't support extra syntax (ex. `jinja2[diagrams]`), if such
86
- extra is present in the dependency, we mark it as unavailable.
87
- """
88
- if not package.name or package.extras:
89
- return False
90
- if package.name not in self._packages:
91
- return False
92
- if skip_version_check or not package.specs:
93
- return True
94
- return self._packages[package.name].is_required_version_available(package)
95
-
96
- def package_latest_version(self, package: Requirement) -> str | None:
97
- """Returns the latest version of the package or None if the latest version can't be determined."""
98
- if package.name not in self._packages:
99
- return None
100
- try:
101
- return str(max(self._packages[package.name].iter_versions()))
102
- except InvalidVersion:
103
- # fail-safe for non-pep8 versions
104
- return None
105
-
106
- def package_versions(self, package: Requirement) -> List[str]:
107
- """Returns list of available versions of the package."""
108
- if package.name not in self._packages:
109
- return []
110
- package_data = self._packages[package.name]
111
- try:
112
- return list(
113
- str(x) for x in sorted(package_data.iter_versions(), reverse=True)
114
- )
115
- except InvalidVersion:
116
- return list(sorted(package_data.versions, reverse=True))
117
-
118
- def filter_available_packages(
119
- self, packages: List[Requirement], skip_version_check: bool = False
120
- ) -> FilterRequirementsResult:
121
- """
122
- Checks if a list of packages are available in the Snowflake Anaconda channel.
123
- Returns an object with two attributes: 'snowflake' and 'other'.
124
- Each key contains a list of Requirement object.
125
-
126
- Parameters:
127
- packages (List[Requirement]) - list of requirements to be checked
128
- skip_version_check (bool) - skip comparing versions of packages
129
-
130
- Returns:
131
- result (FilterRequirementsResult) - object containing two arguments:
132
- - in_snowflake - packages available in conda
133
- - unavailable - packages not available in conda
134
- """
135
- result = FilterRequirementsResult([], [])
136
- for package in packages:
137
- if self.is_package_available(
138
- package, skip_version_check=skip_version_check
139
- ):
140
- result.in_snowflake.append(package)
141
- else:
142
- log.info(
143
- "'%s' not found in Snowflake Anaconda channel (or ignored)...",
144
- package.name,
145
- )
146
- result.unavailable.append(package)
147
- return result
148
-
149
- def write_requirements_file_in_snowflake_format(
150
- self,
151
- file_path: SecurePath,
152
- requirements: List[Requirement],
153
- ):
154
- """Saves requirements to a file in format accepted by Snowflake SQL commands."""
155
- log.info("Writing requirements into file %s", file_path.path)
156
- formatted_requirements = []
157
- for requirement in requirements:
158
- if requirement.name and requirement.name in self._packages:
159
- snowflake_name = self._packages[requirement.name].snowflake_name
160
- formatted_requirements.append(
161
- snowflake_name + requirement.formatted_specs
162
- )
163
-
164
- if formatted_requirements:
165
- file_path.write_text("\n".join(formatted_requirements))
166
-
167
-
168
- class AnacondaPackagesManager(SqlExecutionMixin):
169
- _snowflake_channel_url: str = (
170
- "https://repo.anaconda.com/pkgs/snowflake/channeldata.json"
171
- )
172
-
173
- # TODO in v3.0: Keep only SQL query, remove fallback to JSON with channel's metadata
174
- def find_packages_available_in_snowflake_anaconda(self) -> AnacondaPackages:
175
- """
176
- Finds python packages available in Snowflake to use in functions and stored procedures.
177
- It tries to get the list of packages using SQL query
178
- but if the try fails then the fallback is to parse JSON containing info about Snowflake's Anaconda channel.
179
- """
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()
190
- return AnacondaPackages(packages)
191
-
192
- def _query_snowflake_for_available_packages(self) -> dict[str, AvailablePackage]:
193
- cursor = self._execute_query(
194
- "select package_name, version from information_schema.packages where language = 'python'",
195
- cursor_class=DictCursor,
196
- )
197
- if cursor.rowcount is None or cursor.rowcount == 0:
198
- raise SnowflakeSQLExecutionError()
199
- packages: dict[str, AvailablePackage] = {}
200
- for row in cursor:
201
- if not (package_name := row["PACKAGE_NAME"]):
202
- continue
203
- if not (version := row["VERSION"]):
204
- continue
205
- standardized_name = Requirement.standardize_name(package_name)
206
- if standardized_name in packages:
207
- packages[standardized_name].versions.add(version)
208
- else:
209
- packages[standardized_name] = AvailablePackage(
210
- snowflake_name=package_name, versions={version}
211
- )
212
- 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
- )
@@ -1,256 +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 logging
18
- from pathlib import Path
19
- from textwrap import dedent
20
- from typing import Optional
21
-
22
- import typer
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 (
31
- Requirement,
32
- YesNoAsk,
33
- )
34
- from snowflake.cli.plugins.snowpark.package.anaconda_packages import (
35
- AnacondaPackages,
36
- AnacondaPackagesManager,
37
- )
38
- from snowflake.cli.plugins.snowpark.package.manager import upload
39
- from snowflake.cli.plugins.snowpark.package_utils import (
40
- detect_and_log_shared_libraries,
41
- download_unavailable_packages,
42
- get_package_name_from_pip_wheel,
43
- )
44
- from snowflake.cli.plugins.snowpark.snowpark_shared import (
45
- AllowSharedLibrariesOption,
46
- IgnoreAnacondaOption,
47
- IndexUrlOption,
48
- SkipVersionCheckOption,
49
- deprecated_allow_native_libraries_option,
50
- resolve_allow_shared_libraries_yes_no_ask,
51
- )
52
- from snowflake.cli.plugins.snowpark.zipper import zip_dir
53
-
54
- app = SnowTyperFactory(
55
- name="package",
56
- help="Manages custom Python packages for Snowpark",
57
- )
58
- log = logging.getLogger(__name__)
59
-
60
-
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
- @app.command("lookup", requires_connection=True)
84
- def package_lookup(
85
- package_name: str = typer.Argument(
86
- ..., help="Name of the package.", show_default=False
87
- ),
88
- # todo: remove with 3.0
89
- _: bool = lookup_install_option,
90
- __: bool = lookup_deprecated_install_option,
91
- **options,
92
- ) -> CommandResult:
93
- """
94
- Checks if a package is available on the Snowflake Anaconda channel.
95
- """
96
- anaconda_packages_manager = AnacondaPackagesManager()
97
- anaconda_packages = (
98
- anaconda_packages_manager.find_packages_available_in_snowflake_anaconda()
99
- )
100
-
101
- package = Requirement.parse(package_name)
102
- if anaconda_packages.is_package_available(package=package):
103
- msg = f"Package `{package_name}` is available in Anaconda"
104
- if version := anaconda_packages.package_latest_version(package=package):
105
- msg += f". Latest available version: {version}."
106
- elif versions := anaconda_packages.package_versions(package=package):
107
- msg += f" in versions: {', '.join(versions)}."
108
- return MessageResult(msg)
109
-
110
- return MessageResult(
111
- dedent(
112
- f"""
113
- Package `{package_name}` is not available in Anaconda. To prepare Snowpark compatible package run:
114
- snow snowpark package create {package_name}
115
- """
116
- )
117
- )
118
-
119
-
120
- @app.command("upload", requires_connection=True)
121
- def package_upload(
122
- file: Path = typer.Option(
123
- ...,
124
- "--file",
125
- "-f",
126
- help="Path to the file to upload.",
127
- exists=False,
128
- ),
129
- stage: str = typer.Option(
130
- ...,
131
- "--stage",
132
- "-s",
133
- help="Name of the stage in which to upload the file, not including the @ symbol.",
134
- ),
135
- overwrite: bool = typer.Option(
136
- False,
137
- "--overwrite",
138
- "-o",
139
- help="Overwrites the file if it already exists.",
140
- ),
141
- **options,
142
- ) -> CommandResult:
143
- """
144
- Uploads a Python package zip file to a Snowflake stage so it can be referenced in the imports of a procedure or function.
145
- """
146
- return MessageResult(upload(file=file, stage=stage, overwrite=overwrite))
147
-
148
-
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
- @app.command("create", requires_connection=True)
172
- def package_create(
173
- name: str = typer.Argument(
174
- ...,
175
- help="Name of the package to create.",
176
- ),
177
- ignore_anaconda: bool = IgnoreAnacondaOption,
178
- index_url: Optional[str] = IndexUrlOption,
179
- skip_version_check: bool = SkipVersionCheckOption,
180
- 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
- **options,
187
- ) -> CommandResult:
188
- """
189
- Creates a Python package as a zip file that can be uploaded to a stage and imported for a Snowpark Python app.
190
- """
191
- with SecurePath.temporary_directory() as packages_dir:
192
- package = Requirement.parse(name)
193
- anaconda_packages_manager = AnacondaPackagesManager()
194
- download_result = download_unavailable_packages(
195
- requirements=[package],
196
- target_dir=packages_dir,
197
- anaconda_packages=(
198
- AnacondaPackages.empty()
199
- if ignore_anaconda
200
- else anaconda_packages_manager.find_packages_available_in_snowflake_anaconda()
201
- ),
202
- skip_version_check=skip_version_check,
203
- pip_index_url=index_url,
204
- )
205
- if not download_result.succeeded:
206
- raise ClickException(download_result.error_message)
207
-
208
- # check if package was detected as available
209
- package_available_in_conda = any(
210
- p.line == package.line for p in download_result.anaconda_packages
211
- )
212
- if package_available_in_conda:
213
- return MessageResult(
214
- f"Package {name} is already available in Snowflake Anaconda Channel."
215
- )
216
-
217
- # The package is not in anaconda, so we have to pack it
218
- log.info("Checking to see if packages have shared (.so/.dll) libraries...")
219
- 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
- ):
227
- raise ClickException(
228
- "Some packages contain shared (.so/.dll) libraries. "
229
- "Try again with --allow-shared-libraries."
230
- )
231
-
232
- # The package is not in anaconda, so we have to pack it
233
- # the package was downloaded once, pip wheel should use cache
234
- zip_file = f"{get_package_name_from_pip_wheel(name, index_url=index_url)}.zip"
235
- zip_dir(dest_zip=Path(zip_file), source=packages_dir.path)
236
- message = dedent(
237
- f"""
238
- Package {zip_file} created. You can now upload it to a stage using
239
- snow snowpark package upload -f {zip_file} -s <stage-name>`
240
- and reference it in your procedure or function.
241
- Remember to add it to imports in the procedure or function definition.
242
- """
243
- )
244
- if download_result.anaconda_packages:
245
- message += dedent(
246
- f"""
247
- The package {name} is successfully created, but depends on the following
248
- Anaconda libraries. They need to be included in project requirements,
249
- as their are not included in .zip.
250
- """
251
- )
252
- message += "\n".join(
253
- (req.line for req in download_result.anaconda_packages)
254
- )
255
-
256
- return MessageResult(message)
@@ -1,43 +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 logging
18
- from pathlib import Path
19
-
20
- 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
- log = logging.getLogger(__name__)
25
-
26
-
27
- def upload(file: Path, stage: str, overwrite: bool):
28
- log.info("Uploading %s to Snowflake @%s/%s...", file, stage, file)
29
- with SecurePath.temporary_directory() as temp_dir:
30
- temp_app_zip_path = prepare_app_zip(SecurePath(file), temp_dir)
31
- sm = StageManager()
32
-
33
- sm.create(sm.get_stage_from_path(stage))
34
- put_response = sm.put(
35
- temp_app_zip_path.path, stage, overwrite=overwrite
36
- ).fetchone()
37
-
38
- message = f"Package {file} {put_response[6]} to Snowflake @{stage}/{file}."
39
-
40
- if put_response[6] == "SKIPPED":
41
- message = "Package already exists on stage. Consider using --overwrite to overwrite the file."
42
-
43
- return message
@@ -1,26 +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 snowflake.cli.api.secure_path import SecurePath
18
-
19
-
20
- def prepare_app_zip(file_path: SecurePath, temp_dir: SecurePath) -> SecurePath:
21
- # get filename from file path (e.g. app.zip from /path/to/app.zip)
22
- # TODO: think if no file exceptions are handled correctly
23
- file_name = file_path.path.name
24
- temp_path = temp_dir / file_name
25
- file_path.copy(temp_path.path)
26
- return temp_path