snowflake-cli 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 (240) hide show
  1. snowflake/cli/__about__.py +17 -0
  2. snowflake/cli/__init__.py +13 -0
  3. snowflake/cli/api/__init__.py +48 -0
  4. snowflake/cli/api/cli_global_context.py +390 -0
  5. snowflake/cli/api/commands/__init__.py +13 -0
  6. snowflake/cli/api/commands/alias.py +23 -0
  7. snowflake/cli/api/commands/decorators.py +354 -0
  8. snowflake/cli/api/commands/execution_metadata.py +40 -0
  9. snowflake/cli/api/commands/experimental_behaviour.py +19 -0
  10. snowflake/cli/api/commands/flags.py +662 -0
  11. snowflake/cli/api/commands/project_initialisation.py +65 -0
  12. snowflake/cli/api/commands/snow_typer.py +237 -0
  13. snowflake/cli/api/commands/typer_pre_execute.py +26 -0
  14. snowflake/cli/api/config.py +348 -0
  15. snowflake/cli/api/console/__init__.py +17 -0
  16. snowflake/cli/api/console/abc.py +89 -0
  17. snowflake/cli/api/console/console.py +134 -0
  18. snowflake/cli/api/console/enum.py +17 -0
  19. snowflake/cli/api/constants.py +79 -0
  20. snowflake/cli/api/errno.py +27 -0
  21. snowflake/cli/api/exceptions.py +164 -0
  22. snowflake/cli/api/feature_flags.py +55 -0
  23. snowflake/cli/api/identifiers.py +167 -0
  24. snowflake/cli/api/output/__init__.py +13 -0
  25. snowflake/cli/api/output/formats.py +20 -0
  26. snowflake/cli/api/output/types.py +118 -0
  27. snowflake/cli/api/plugins/__init__.py +13 -0
  28. snowflake/cli/api/plugins/command/__init__.py +72 -0
  29. snowflake/cli/api/plugins/command/plugin_hook_specs.py +21 -0
  30. snowflake/cli/api/plugins/plugin_config.py +32 -0
  31. snowflake/cli/api/project/__init__.py +13 -0
  32. snowflake/cli/api/project/definition.py +84 -0
  33. snowflake/cli/api/project/definition_manager.py +134 -0
  34. snowflake/cli/api/project/errors.py +56 -0
  35. snowflake/cli/api/project/project_verification.py +23 -0
  36. snowflake/cli/api/project/schemas/__init__.py +13 -0
  37. snowflake/cli/api/project/schemas/entities/application_entity.py +44 -0
  38. snowflake/cli/api/project/schemas/entities/application_package_entity.py +66 -0
  39. snowflake/cli/api/project/schemas/entities/common.py +78 -0
  40. snowflake/cli/api/project/schemas/entities/entities.py +30 -0
  41. snowflake/cli/api/project/schemas/identifier_model.py +49 -0
  42. snowflake/cli/api/project/schemas/native_app/__init__.py +13 -0
  43. snowflake/cli/api/project/schemas/native_app/application.py +62 -0
  44. snowflake/cli/api/project/schemas/native_app/native_app.py +93 -0
  45. snowflake/cli/api/project/schemas/native_app/package.py +78 -0
  46. snowflake/cli/api/project/schemas/native_app/path_mapping.py +65 -0
  47. snowflake/cli/api/project/schemas/project_definition.py +199 -0
  48. snowflake/cli/api/project/schemas/snowpark/__init__.py +13 -0
  49. snowflake/cli/api/project/schemas/snowpark/argument.py +28 -0
  50. snowflake/cli/api/project/schemas/snowpark/callable.py +69 -0
  51. snowflake/cli/api/project/schemas/snowpark/snowpark.py +36 -0
  52. snowflake/cli/api/project/schemas/streamlit/__init__.py +13 -0
  53. snowflake/cli/api/project/schemas/streamlit/streamlit.py +46 -0
  54. snowflake/cli/api/project/schemas/template.py +77 -0
  55. snowflake/cli/api/project/schemas/updatable_model.py +194 -0
  56. snowflake/cli/api/project/util.py +261 -0
  57. snowflake/cli/api/rendering/__init__.py +13 -0
  58. snowflake/cli/api/rendering/jinja.py +112 -0
  59. snowflake/cli/api/rendering/project_definition_templates.py +39 -0
  60. snowflake/cli/api/rendering/project_templates.py +98 -0
  61. snowflake/cli/api/rendering/sql_templates.py +60 -0
  62. snowflake/cli/api/rest_api.py +172 -0
  63. snowflake/cli/api/sanitizers.py +43 -0
  64. snowflake/cli/api/secure_path.py +362 -0
  65. snowflake/cli/api/secure_utils.py +29 -0
  66. snowflake/cli/api/sql_execution.py +260 -0
  67. snowflake/cli/api/utils/__init__.py +13 -0
  68. snowflake/cli/api/utils/cursor.py +34 -0
  69. snowflake/cli/api/utils/definition_rendering.py +383 -0
  70. snowflake/cli/api/utils/dict_utils.py +73 -0
  71. snowflake/cli/api/utils/error_handling.py +23 -0
  72. snowflake/cli/api/utils/graph.py +97 -0
  73. snowflake/cli/api/utils/models.py +63 -0
  74. snowflake/cli/api/utils/naming_utils.py +13 -0
  75. snowflake/cli/api/utils/path_utils.py +36 -0
  76. snowflake/cli/api/utils/templating_functions.py +144 -0
  77. snowflake/cli/api/utils/types.py +35 -0
  78. snowflake/cli/app/__init__.py +22 -0
  79. snowflake/cli/app/__main__.py +31 -0
  80. snowflake/cli/app/api_impl/__init__.py +13 -0
  81. snowflake/cli/app/api_impl/plugin/__init__.py +13 -0
  82. snowflake/cli/app/api_impl/plugin/plugin_config_provider_impl.py +66 -0
  83. snowflake/cli/app/build_and_push.sh +8 -0
  84. snowflake/cli/app/cli_app.py +243 -0
  85. snowflake/cli/app/commands_registration/__init__.py +33 -0
  86. snowflake/cli/app/commands_registration/builtin_plugins.py +54 -0
  87. snowflake/cli/app/commands_registration/command_plugins_loader.py +169 -0
  88. snowflake/cli/app/commands_registration/commands_registration_with_callbacks.py +105 -0
  89. snowflake/cli/app/commands_registration/exception_logging.py +26 -0
  90. snowflake/cli/app/commands_registration/threadsafe.py +48 -0
  91. snowflake/cli/app/commands_registration/typer_registration.py +153 -0
  92. snowflake/cli/app/constants.py +19 -0
  93. snowflake/cli/app/dev/__init__.py +13 -0
  94. snowflake/cli/app/dev/commands_structure.py +48 -0
  95. snowflake/cli/app/dev/docs/__init__.py +13 -0
  96. snowflake/cli/app/dev/docs/commands_docs_generator.py +100 -0
  97. snowflake/cli/app/dev/docs/generator.py +35 -0
  98. snowflake/cli/app/dev/docs/project_definition_docs_generator.py +58 -0
  99. snowflake/cli/app/dev/docs/project_definition_generate_json_schema.py +227 -0
  100. snowflake/cli/app/dev/docs/template_utils.py +23 -0
  101. snowflake/cli/app/dev/docs/templates/definition_description.rst.jinja2 +38 -0
  102. snowflake/cli/app/dev/docs/templates/overview.rst.jinja2 +9 -0
  103. snowflake/cli/app/dev/docs/templates/usage.rst.jinja2 +57 -0
  104. snowflake/cli/app/dev/pycharm_remote_debug.py +46 -0
  105. snowflake/cli/app/loggers.py +199 -0
  106. snowflake/cli/app/main_typer.py +62 -0
  107. snowflake/cli/app/printing.py +181 -0
  108. snowflake/cli/app/snow_connector.py +243 -0
  109. snowflake/cli/app/telemetry.py +189 -0
  110. snowflake/cli/plugins/__init__.py +13 -0
  111. snowflake/cli/plugins/connection/__init__.py +13 -0
  112. snowflake/cli/plugins/connection/commands.py +330 -0
  113. snowflake/cli/plugins/connection/plugin_spec.py +30 -0
  114. snowflake/cli/plugins/connection/util.py +179 -0
  115. snowflake/cli/plugins/cortex/__init__.py +13 -0
  116. snowflake/cli/plugins/cortex/commands.py +327 -0
  117. snowflake/cli/plugins/cortex/constants.py +17 -0
  118. snowflake/cli/plugins/cortex/manager.py +189 -0
  119. snowflake/cli/plugins/cortex/plugin_spec.py +30 -0
  120. snowflake/cli/plugins/cortex/types.py +22 -0
  121. snowflake/cli/plugins/git/__init__.py +13 -0
  122. snowflake/cli/plugins/git/commands.py +354 -0
  123. snowflake/cli/plugins/git/manager.py +105 -0
  124. snowflake/cli/plugins/git/plugin_spec.py +30 -0
  125. snowflake/cli/plugins/init/__init__.py +13 -0
  126. snowflake/cli/plugins/init/commands.py +248 -0
  127. snowflake/cli/plugins/init/plugin_spec.py +30 -0
  128. snowflake/cli/plugins/nativeapp/__init__.py +13 -0
  129. snowflake/cli/plugins/nativeapp/artifacts.py +742 -0
  130. snowflake/cli/plugins/nativeapp/codegen/__init__.py +13 -0
  131. snowflake/cli/plugins/nativeapp/codegen/artifact_processor.py +91 -0
  132. snowflake/cli/plugins/nativeapp/codegen/compiler.py +130 -0
  133. snowflake/cli/plugins/nativeapp/codegen/sandbox.py +306 -0
  134. snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +172 -0
  135. snowflake/cli/plugins/nativeapp/codegen/setup/setup_driver.py.source +56 -0
  136. snowflake/cli/plugins/nativeapp/codegen/snowpark/callback_source.py.jinja +181 -0
  137. snowflake/cli/plugins/nativeapp/codegen/snowpark/extension_function_utils.py +217 -0
  138. snowflake/cli/plugins/nativeapp/codegen/snowpark/models.py +61 -0
  139. snowflake/cli/plugins/nativeapp/codegen/snowpark/python_processor.py +528 -0
  140. snowflake/cli/plugins/nativeapp/commands.py +439 -0
  141. snowflake/cli/plugins/nativeapp/common_flags.py +44 -0
  142. snowflake/cli/plugins/nativeapp/constants.py +27 -0
  143. snowflake/cli/plugins/nativeapp/exceptions.py +122 -0
  144. snowflake/cli/plugins/nativeapp/feature_flags.py +24 -0
  145. snowflake/cli/plugins/nativeapp/init.py +345 -0
  146. snowflake/cli/plugins/nativeapp/manager.py +823 -0
  147. snowflake/cli/plugins/nativeapp/plugin_spec.py +30 -0
  148. snowflake/cli/plugins/nativeapp/policy.py +50 -0
  149. snowflake/cli/plugins/nativeapp/project_model.py +195 -0
  150. snowflake/cli/plugins/nativeapp/run_processor.py +389 -0
  151. snowflake/cli/plugins/nativeapp/teardown_processor.py +301 -0
  152. snowflake/cli/plugins/nativeapp/utils.py +98 -0
  153. snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +135 -0
  154. snowflake/cli/plugins/nativeapp/version/__init__.py +13 -0
  155. snowflake/cli/plugins/nativeapp/version/commands.py +170 -0
  156. snowflake/cli/plugins/nativeapp/version/version_processor.py +362 -0
  157. snowflake/cli/plugins/notebook/__init__.py +13 -0
  158. snowflake/cli/plugins/notebook/commands.py +85 -0
  159. snowflake/cli/plugins/notebook/exceptions.py +20 -0
  160. snowflake/cli/plugins/notebook/manager.py +71 -0
  161. snowflake/cli/plugins/notebook/plugin_spec.py +30 -0
  162. snowflake/cli/plugins/notebook/types.py +15 -0
  163. snowflake/cli/plugins/object/__init__.py +13 -0
  164. snowflake/cli/plugins/object/command_aliases.py +95 -0
  165. snowflake/cli/plugins/object/commands.py +181 -0
  166. snowflake/cli/plugins/object/common.py +85 -0
  167. snowflake/cli/plugins/object/manager.py +97 -0
  168. snowflake/cli/plugins/object/plugin_spec.py +30 -0
  169. snowflake/cli/plugins/object_stage_deprecated/__init__.py +15 -0
  170. snowflake/cli/plugins/object_stage_deprecated/commands.py +122 -0
  171. snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +32 -0
  172. snowflake/cli/plugins/snowpark/__init__.py +13 -0
  173. snowflake/cli/plugins/snowpark/commands.py +546 -0
  174. snowflake/cli/plugins/snowpark/common.py +307 -0
  175. snowflake/cli/plugins/snowpark/manager.py +109 -0
  176. snowflake/cli/plugins/snowpark/models.py +157 -0
  177. snowflake/cli/plugins/snowpark/package/__init__.py +13 -0
  178. snowflake/cli/plugins/snowpark/package/anaconda_packages.py +233 -0
  179. snowflake/cli/plugins/snowpark/package/commands.py +256 -0
  180. snowflake/cli/plugins/snowpark/package/manager.py +44 -0
  181. snowflake/cli/plugins/snowpark/package/utils.py +26 -0
  182. snowflake/cli/plugins/snowpark/package_utils.py +354 -0
  183. snowflake/cli/plugins/snowpark/plugin_spec.py +30 -0
  184. snowflake/cli/plugins/snowpark/snowpark_package_paths.py +65 -0
  185. snowflake/cli/plugins/snowpark/snowpark_shared.py +95 -0
  186. snowflake/cli/plugins/snowpark/zipper.py +81 -0
  187. snowflake/cli/plugins/spcs/__init__.py +35 -0
  188. snowflake/cli/plugins/spcs/common.py +99 -0
  189. snowflake/cli/plugins/spcs/compute_pool/__init__.py +13 -0
  190. snowflake/cli/plugins/spcs/compute_pool/commands.py +241 -0
  191. snowflake/cli/plugins/spcs/compute_pool/manager.py +121 -0
  192. snowflake/cli/plugins/spcs/image_registry/__init__.py +13 -0
  193. snowflake/cli/plugins/spcs/image_registry/commands.py +65 -0
  194. snowflake/cli/plugins/spcs/image_registry/manager.py +105 -0
  195. snowflake/cli/plugins/spcs/image_repository/__init__.py +13 -0
  196. snowflake/cli/plugins/spcs/image_repository/commands.py +202 -0
  197. snowflake/cli/plugins/spcs/image_repository/manager.py +84 -0
  198. snowflake/cli/plugins/spcs/jobs/__init__.py +13 -0
  199. snowflake/cli/plugins/spcs/jobs/commands.py +78 -0
  200. snowflake/cli/plugins/spcs/jobs/manager.py +53 -0
  201. snowflake/cli/plugins/spcs/plugin_spec.py +30 -0
  202. snowflake/cli/plugins/spcs/services/__init__.py +13 -0
  203. snowflake/cli/plugins/spcs/services/commands.py +312 -0
  204. snowflake/cli/plugins/spcs/services/manager.py +170 -0
  205. snowflake/cli/plugins/sql/__init__.py +13 -0
  206. snowflake/cli/plugins/sql/commands.py +83 -0
  207. snowflake/cli/plugins/sql/manager.py +92 -0
  208. snowflake/cli/plugins/sql/plugin_spec.py +30 -0
  209. snowflake/cli/plugins/sql/snowsql_templating.py +28 -0
  210. snowflake/cli/plugins/stage/__init__.py +13 -0
  211. snowflake/cli/plugins/stage/commands.py +263 -0
  212. snowflake/cli/plugins/stage/diff.py +326 -0
  213. snowflake/cli/plugins/stage/manager.py +577 -0
  214. snowflake/cli/plugins/stage/md5.py +160 -0
  215. snowflake/cli/plugins/stage/plugin_spec.py +30 -0
  216. snowflake/cli/plugins/streamlit/__init__.py +13 -0
  217. snowflake/cli/plugins/streamlit/commands.py +179 -0
  218. snowflake/cli/plugins/streamlit/manager.py +222 -0
  219. snowflake/cli/plugins/streamlit/plugin_spec.py +30 -0
  220. snowflake/cli/plugins/workspace/__init__.py +13 -0
  221. snowflake/cli/plugins/workspace/commands.py +35 -0
  222. snowflake/cli/plugins/workspace/plugin_spec.py +30 -0
  223. snowflake/cli/templates/default_snowpark/.gitignore +4 -0
  224. snowflake/cli/templates/default_snowpark/app/__init__.py +0 -0
  225. snowflake/cli/templates/default_snowpark/app/common.py +2 -0
  226. snowflake/cli/templates/default_snowpark/app/functions.py +15 -0
  227. snowflake/cli/templates/default_snowpark/app/procedures.py +22 -0
  228. snowflake/cli/templates/default_snowpark/requirements.txt +1 -0
  229. snowflake/cli/templates/default_snowpark/snowflake.yml +23 -0
  230. snowflake/cli/templates/default_streamlit/.gitignore +4 -0
  231. snowflake/cli/templates/default_streamlit/common/hello.py +2 -0
  232. snowflake/cli/templates/default_streamlit/environment.yml +6 -0
  233. snowflake/cli/templates/default_streamlit/pages/my_page.py +3 -0
  234. snowflake/cli/templates/default_streamlit/snowflake.yml +10 -0
  235. snowflake/cli/templates/default_streamlit/streamlit_app.py +4 -0
  236. snowflake_cli-2.8.2.dist-info/METADATA +325 -0
  237. snowflake_cli-2.8.2.dist-info/RECORD +240 -0
  238. snowflake_cli-2.8.2.dist-info/WHEEL +4 -0
  239. snowflake_cli-2.8.2.dist-info/entry_points.txt +2 -0
  240. snowflake_cli-2.8.2.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,243 @@
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 platform
19
+ import sys
20
+ from dataclasses import dataclass
21
+ from pathlib import Path
22
+ from typing import Optional
23
+
24
+ import click
25
+ import typer
26
+ from click import Context
27
+ from snowflake.cli import __about__
28
+ from snowflake.cli.api import Api, api_provider
29
+ from snowflake.cli.api.config import config_init
30
+ from snowflake.cli.api.output.formats import OutputFormat
31
+ from snowflake.cli.api.output.types import CollectionResult
32
+ from snowflake.cli.api.secure_path import SecurePath
33
+ from snowflake.cli.app.api_impl.plugin.plugin_config_provider_impl import (
34
+ PluginConfigProviderImpl,
35
+ )
36
+ from snowflake.cli.app.commands_registration.commands_registration_with_callbacks import (
37
+ CommandsRegistrationWithCallbacks,
38
+ )
39
+ from snowflake.cli.app.dev.commands_structure import generate_commands_structure
40
+ from snowflake.cli.app.dev.docs.generator import generate_docs
41
+ from snowflake.cli.app.dev.pycharm_remote_debug import (
42
+ setup_pycharm_remote_debugger_if_provided,
43
+ )
44
+ from snowflake.cli.app.main_typer import SnowCliMainTyper
45
+ from snowflake.cli.app.printing import MessageResult, print_result
46
+ from snowflake.connector.config_manager import CONFIG_MANAGER
47
+
48
+ log = logging.getLogger(__name__)
49
+
50
+ _api = Api(plugin_config_provider=PluginConfigProviderImpl())
51
+ api_provider.register_api(_api)
52
+
53
+ _commands_registration = CommandsRegistrationWithCallbacks(_api.plugin_config_provider)
54
+
55
+
56
+ @dataclass
57
+ class AppContextHolder:
58
+ # needed to access the context from tests
59
+ app_context: Optional[Context] = None
60
+
61
+
62
+ app_context_holder = AppContextHolder()
63
+
64
+
65
+ def _exit_with_cleanup():
66
+ _commands_registration.reset_running_instance_registration_state()
67
+ raise typer.Exit()
68
+
69
+
70
+ def _do_not_execute_on_completion(callback):
71
+ def enriched_callback(value):
72
+ if click.get_current_context().resilient_parsing:
73
+ return
74
+ callback(value)
75
+
76
+ return enriched_callback
77
+
78
+
79
+ def _commands_registration_callback(value: bool):
80
+ if value:
81
+ _commands_registration.register_commands_if_ready_and_not_registered_yet()
82
+ # required to make the tests working
83
+ # because a single test can execute multiple commands using always the same "app" instance
84
+ _commands_registration.reset_running_instance_registration_state()
85
+ app_context_holder.app_context = click.get_current_context()
86
+
87
+
88
+ @_commands_registration.before
89
+ def _config_init_callback(configuration_file: Optional[Path]):
90
+ config_init(configuration_file)
91
+
92
+
93
+ @_commands_registration.before
94
+ def _disable_external_command_plugins_callback(value: bool):
95
+ if value:
96
+ _commands_registration.disable_external_command_plugins()
97
+
98
+
99
+ @_do_not_execute_on_completion
100
+ @_commands_registration.after
101
+ def _docs_callback(value: bool):
102
+ if value:
103
+ ctx = click.get_current_context()
104
+ generate_docs(SecurePath("gen_docs"), ctx.command)
105
+ _exit_with_cleanup()
106
+
107
+
108
+ @_do_not_execute_on_completion
109
+ @_commands_registration.after
110
+ def _commands_structure_callback(value: bool):
111
+ if value:
112
+ ctx = click.get_current_context()
113
+ generate_commands_structure(ctx.command).print_node()
114
+ _exit_with_cleanup()
115
+
116
+
117
+ @_do_not_execute_on_completion
118
+ def _version_callback(value: bool):
119
+ if value:
120
+ print_result(MessageResult(f"Snowflake CLI version: {__about__.VERSION}"))
121
+ _exit_with_cleanup()
122
+
123
+
124
+ from snowflake.cli.api.config import get_feature_flags_section
125
+
126
+
127
+ @_do_not_execute_on_completion
128
+ def _info_callback(value: bool):
129
+ if value:
130
+ result = CollectionResult(
131
+ [
132
+ {"key": "version", "value": __about__.VERSION},
133
+ {
134
+ "key": "default_config_file_path",
135
+ "value": str(CONFIG_MANAGER.file_path),
136
+ },
137
+ {"key": "python_version", "value": sys.version},
138
+ {"key": "system_info", "value": platform.platform()},
139
+ {"key": "feature_flags", "value": get_feature_flags_section()},
140
+ ],
141
+ )
142
+ print_result(result, output_format=OutputFormat.JSON)
143
+ _exit_with_cleanup()
144
+
145
+
146
+ def app_factory() -> SnowCliMainTyper:
147
+ app = SnowCliMainTyper()
148
+
149
+ @app.callback(invoke_without_command=True)
150
+ def default(
151
+ ctx: typer.Context,
152
+ version: bool = typer.Option(
153
+ None,
154
+ "--version",
155
+ help="Shows version of the Snowflake CLI",
156
+ callback=_version_callback,
157
+ is_eager=True,
158
+ ),
159
+ docs: bool = typer.Option(
160
+ None,
161
+ "--docs",
162
+ hidden=True,
163
+ help="Generates Snowflake CLI documentation",
164
+ callback=_docs_callback,
165
+ is_eager=True,
166
+ ),
167
+ structure: bool = typer.Option(
168
+ None,
169
+ "--structure",
170
+ hidden=True,
171
+ help="Prints Snowflake CLI structure of commands",
172
+ callback=_commands_structure_callback,
173
+ is_eager=True,
174
+ ),
175
+ info: bool = typer.Option(
176
+ None,
177
+ "--info",
178
+ help="Shows information about the Snowflake CLI",
179
+ callback=_info_callback,
180
+ ),
181
+ configuration_file: Path = typer.Option(
182
+ None,
183
+ "--config-file",
184
+ help="Specifies Snowflake CLI configuration file that should be used",
185
+ exists=True,
186
+ dir_okay=False,
187
+ is_eager=True,
188
+ callback=_config_init_callback,
189
+ ),
190
+ pycharm_debug_library_path: str = typer.Option(
191
+ None,
192
+ "--pycharm-debug-library-path",
193
+ hidden=True,
194
+ ),
195
+ pycharm_debug_server_host: str = typer.Option(
196
+ "localhost",
197
+ "--pycharm-debug-server-host",
198
+ hidden=True,
199
+ ),
200
+ pycharm_debug_server_port: int = typer.Option(
201
+ 12345,
202
+ "--pycharm-debug-server-port",
203
+ hidden=True,
204
+ ),
205
+ disable_external_command_plugins: bool = typer.Option(
206
+ None,
207
+ "--disable-external-command-plugins",
208
+ help="Disable external command plugins",
209
+ callback=_disable_external_command_plugins_callback,
210
+ is_eager=True,
211
+ hidden=True,
212
+ ),
213
+ # THIS OPTION SHOULD BE THE LAST OPTION IN THE LIST!
214
+ # ---
215
+ # This is a hidden artificial option used only to guarantee execution of commands registration
216
+ # and make this guaranty not dependent on other callbacks.
217
+ # Commands registration is invoked as soon as all callbacks
218
+ # decorated with "_commands_registration.before" are executed
219
+ # but if there are no such callbacks (at the result of possible future changes)
220
+ # then we need to invoke commands registration manually.
221
+ #
222
+ # This option is also responsible for resetting registration state for test purposes.
223
+ commands_registration: bool = typer.Option(
224
+ True,
225
+ "--commands-registration",
226
+ help="Commands registration",
227
+ hidden=True,
228
+ is_eager=True,
229
+ callback=_commands_registration_callback,
230
+ ),
231
+ ) -> None:
232
+ """
233
+ Snowflake CLI tool for developers.
234
+ """
235
+ if not ctx.invoked_subcommand:
236
+ typer.echo(ctx.get_help())
237
+ setup_pycharm_remote_debugger_if_provided(
238
+ pycharm_debug_library_path=pycharm_debug_library_path,
239
+ pycharm_debug_server_host=pycharm_debug_server_host,
240
+ pycharm_debug_server_port=pycharm_debug_server_port,
241
+ )
242
+
243
+ return app
@@ -0,0 +1,33 @@
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 dataclasses import dataclass
16
+
17
+ from snowflake.cli.api.plugins.command import CommandSpec
18
+
19
+
20
+ @dataclass
21
+ class LoadedCommandPlugin:
22
+ plugin_name: str
23
+ command_spec: CommandSpec
24
+
25
+
26
+ @dataclass
27
+ class LoadedBuiltInCommandPlugin(LoadedCommandPlugin):
28
+ pass
29
+
30
+
31
+ @dataclass
32
+ class LoadedExternalCommandPlugin(LoadedCommandPlugin):
33
+ pass
@@ -0,0 +1,54 @@
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 snowflake.cli.plugins.connection import plugin_spec as connection_plugin_spec
16
+ from snowflake.cli.plugins.cortex import plugin_spec as cortex_plugin_spec
17
+ from snowflake.cli.plugins.git import plugin_spec as git_plugin_spec
18
+ from snowflake.cli.plugins.init import plugin_spec as init_plugin_spec
19
+ from snowflake.cli.plugins.nativeapp import plugin_spec as nativeapp_plugin_spec
20
+ from snowflake.cli.plugins.notebook import plugin_spec as notebook_plugin_spec
21
+ from snowflake.cli.plugins.object import plugin_spec as object_plugin_spec
22
+
23
+ # TODO 3.0: remove this import
24
+ from snowflake.cli.plugins.object_stage_deprecated import (
25
+ plugin_spec as object_stage_deprecated_plugin_spec,
26
+ )
27
+ from snowflake.cli.plugins.snowpark import plugin_spec as snowpark_plugin_spec
28
+ from snowflake.cli.plugins.spcs import plugin_spec as spcs_plugin_spec
29
+ from snowflake.cli.plugins.sql import plugin_spec as sql_plugin_spec
30
+ from snowflake.cli.plugins.stage import plugin_spec as stage_plugin_spec
31
+ from snowflake.cli.plugins.streamlit import plugin_spec as streamlit_plugin_spec
32
+ from snowflake.cli.plugins.workspace import plugin_spec as workspace_plugin_spec
33
+
34
+
35
+ # plugin name to plugin spec
36
+ def get_builtin_plugin_name_to_plugin_spec():
37
+ plugin_specs = {
38
+ "connection": connection_plugin_spec,
39
+ "spcs": spcs_plugin_spec,
40
+ "nativeapp": nativeapp_plugin_spec,
41
+ "object": object_plugin_spec,
42
+ "snowpark": snowpark_plugin_spec,
43
+ "stage": stage_plugin_spec,
44
+ "sql": sql_plugin_spec,
45
+ "streamlit": streamlit_plugin_spec,
46
+ "git": git_plugin_spec,
47
+ "notebook": notebook_plugin_spec,
48
+ "object-stage-deprecated": object_stage_deprecated_plugin_spec,
49
+ "cortex": cortex_plugin_spec,
50
+ "init": init_plugin_spec,
51
+ "workspace": workspace_plugin_spec,
52
+ }
53
+
54
+ return plugin_specs
@@ -0,0 +1,169 @@
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 typing import Dict, List, Optional
19
+
20
+ import pluggy
21
+ from snowflake.cli.api.plugins.command import (
22
+ SNOWCLI_COMMAND_PLUGIN_NAMESPACE,
23
+ CommandPath,
24
+ CommandSpec,
25
+ plugin_hook_specs,
26
+ )
27
+ from snowflake.cli.app.commands_registration import (
28
+ LoadedBuiltInCommandPlugin,
29
+ LoadedCommandPlugin,
30
+ LoadedExternalCommandPlugin,
31
+ )
32
+ from snowflake.cli.app.commands_registration.builtin_plugins import (
33
+ get_builtin_plugin_name_to_plugin_spec,
34
+ )
35
+ from snowflake.cli.app.commands_registration.exception_logging import exception_logging
36
+
37
+ log = logging.getLogger(__name__)
38
+ log_exception = exception_logging(log)
39
+
40
+
41
+ class CommandPluginsLoader:
42
+ def __init__(self):
43
+ plugin_manager = pluggy.PluginManager(SNOWCLI_COMMAND_PLUGIN_NAMESPACE)
44
+ plugin_manager.add_hookspecs(plugin_hook_specs)
45
+ self._plugin_manager = plugin_manager
46
+ self._loaded_plugins: Dict[str, LoadedCommandPlugin] = {}
47
+ self._loaded_command_paths: Dict[CommandPath, LoadedCommandPlugin] = {}
48
+
49
+ def register_builtin_plugins(self) -> None:
50
+ for plugin_name, plugin in get_builtin_plugin_name_to_plugin_spec().items():
51
+ try:
52
+ self._plugin_manager.register(plugin=plugin, name=plugin_name)
53
+ except Exception as ex:
54
+ log_exception(
55
+ f"Cannot register plugin [{plugin_name}]: {ex.__str__()}", ex
56
+ )
57
+
58
+ def register_external_plugins(self, plugin_names: List[str]) -> None:
59
+ for plugin_name in plugin_names:
60
+ try:
61
+ self._plugin_manager.load_setuptools_entrypoints(
62
+ SNOWCLI_COMMAND_PLUGIN_NAMESPACE, plugin_name
63
+ )
64
+ except Exception as ex:
65
+ log_exception(
66
+ f"Cannot register plugin [{plugin_name}]: {ex.__str__()}", ex
67
+ )
68
+
69
+ def load_all_registered_plugins(self) -> List[LoadedCommandPlugin]:
70
+ for plugin_name, plugin in self._plugin_manager.list_name_plugin():
71
+ self._load_plugin(plugin_name, plugin)
72
+ return list(self._loaded_plugins.values())
73
+
74
+ def _load_plugin(self, plugin_name: str, plugin) -> Optional[LoadedCommandPlugin]:
75
+ already_loaded_plugin = self._loaded_plugins.get(plugin_name)
76
+ if already_loaded_plugin:
77
+ return already_loaded_plugin
78
+ return self._load_new_plugin(plugin_name, plugin)
79
+
80
+ def _load_new_plugin(
81
+ self, plugin_name: str, plugin
82
+ ) -> Optional[LoadedCommandPlugin]:
83
+ loaded_plugin = self._load_plugin_spec(plugin_name, plugin)
84
+ if not loaded_plugin:
85
+ return None
86
+ other_plugin_with_the_same_command_path = self._loaded_command_paths.get(
87
+ loaded_plugin.command_spec.full_command_path
88
+ )
89
+ if other_plugin_with_the_same_command_path:
90
+ log.error(
91
+ "Cannot load plugin [%s] "
92
+ "because it defines the same command [%s] "
93
+ "as already loaded plugin [%s].",
94
+ plugin_name,
95
+ loaded_plugin.command_spec.full_command_path,
96
+ other_plugin_with_the_same_command_path.plugin_name,
97
+ )
98
+ return None
99
+ self._loaded_plugins[plugin_name] = loaded_plugin
100
+ self._loaded_command_paths[
101
+ loaded_plugin.command_spec.full_command_path
102
+ ] = loaded_plugin
103
+
104
+ if self._is_external_plugin(loaded_plugin):
105
+ log.info("Loaded external plugin: %s", plugin_name)
106
+
107
+ return loaded_plugin
108
+
109
+ def _load_plugin_spec(
110
+ self, plugin_name: str, plugin
111
+ ) -> Optional[LoadedCommandPlugin]:
112
+ if plugin_name in get_builtin_plugin_name_to_plugin_spec().keys():
113
+ return self._load_builtin_plugin_spec(plugin_name, plugin)
114
+ else:
115
+ return self._load_external_plugin_spec(plugin_name, plugin)
116
+
117
+ def _load_builtin_plugin_spec(
118
+ self, plugin_name: str, plugin
119
+ ) -> Optional[LoadedCommandPlugin]:
120
+ command_spec = self._load_command_spec(plugin_name, plugin)
121
+ if command_spec:
122
+ return LoadedBuiltInCommandPlugin(
123
+ plugin_name=plugin_name,
124
+ command_spec=command_spec,
125
+ )
126
+ else:
127
+ return None
128
+
129
+ def _load_external_plugin_spec(
130
+ self, plugin_name: str, plugin
131
+ ) -> Optional[LoadedCommandPlugin]:
132
+ command_spec = self._load_command_spec(plugin_name, plugin)
133
+ if command_spec:
134
+ return LoadedExternalCommandPlugin(
135
+ plugin_name=plugin_name,
136
+ command_spec=command_spec,
137
+ )
138
+ else:
139
+ return None
140
+
141
+ @staticmethod
142
+ def _load_command_spec(plugin_name: str, plugin) -> Optional[CommandSpec]:
143
+ try:
144
+ return plugin.command_spec()
145
+ except Exception as ex:
146
+ log_exception(
147
+ f"Cannot load command specification from plugin [{plugin_name}]: {ex.__str__()}",
148
+ ex,
149
+ )
150
+ return None
151
+
152
+ @staticmethod
153
+ def _is_external_plugin(plugin) -> bool:
154
+ return isinstance(plugin, LoadedExternalCommandPlugin)
155
+
156
+
157
+ def load_only_builtin_command_plugins() -> List[LoadedCommandPlugin]:
158
+ loader = CommandPluginsLoader()
159
+ loader.register_builtin_plugins()
160
+ return loader.load_all_registered_plugins()
161
+
162
+
163
+ def load_builtin_and_external_command_plugins(
164
+ external_plugin_names: List[str],
165
+ ) -> List[LoadedCommandPlugin]:
166
+ loader = CommandPluginsLoader()
167
+ loader.register_builtin_plugins()
168
+ loader.register_external_plugins(external_plugin_names)
169
+ return loader.load_all_registered_plugins()
@@ -0,0 +1,105 @@
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 dataclasses import dataclass
18
+ from typing import Callable, List
19
+
20
+ from snowflake.cli.api.plugins.plugin_config import PluginConfigProvider
21
+ from snowflake.cli.app.commands_registration.command_plugins_loader import (
22
+ load_builtin_and_external_command_plugins,
23
+ load_only_builtin_command_plugins,
24
+ )
25
+ from snowflake.cli.app.commands_registration.threadsafe import ThreadsafeCounter
26
+ from snowflake.cli.app.commands_registration.typer_registration import (
27
+ register_commands_from_plugins,
28
+ )
29
+
30
+
31
+ @dataclass
32
+ class CommandRegistrationConfig:
33
+ enable_external_command_plugins: bool
34
+
35
+
36
+ class CommandsRegistrationWithCallbacks:
37
+ def __init__(self, plugin_config_provider: PluginConfigProvider):
38
+ self._plugin_config_provider = plugin_config_provider
39
+ self._counter_of_callbacks_required_before_registration: ThreadsafeCounter = (
40
+ ThreadsafeCounter(0)
41
+ )
42
+ self._counter_of_callbacks_invoked_before_registration: ThreadsafeCounter = (
43
+ ThreadsafeCounter(0)
44
+ )
45
+ self._callbacks_after_registration: List[Callable[[], None]] = []
46
+ self._commands_registration_config: CommandRegistrationConfig = (
47
+ CommandRegistrationConfig(enable_external_command_plugins=True)
48
+ )
49
+ self._commands_already_registered: bool = False
50
+
51
+ def register_commands_if_ready_and_not_registered_yet(self):
52
+ all_required_callbacks_executed = (
53
+ self._counter_of_callbacks_required_before_registration.value
54
+ == self._counter_of_callbacks_invoked_before_registration.value
55
+ )
56
+ if all_required_callbacks_executed and not self._commands_already_registered:
57
+ self._register_commands_from_plugins()
58
+
59
+ def _register_commands_from_plugins(self) -> None:
60
+ if self._commands_registration_config.enable_external_command_plugins:
61
+ self._register_builtin_and_enabled_external_plugin_commands()
62
+ else:
63
+ self._register_only_builtin_plugin_commands()
64
+
65
+ self._commands_already_registered = True
66
+ for callback in self._callbacks_after_registration:
67
+ callback()
68
+
69
+ @staticmethod
70
+ def _register_only_builtin_plugin_commands() -> None:
71
+ loaded_command_plugins = load_only_builtin_command_plugins()
72
+ register_commands_from_plugins(loaded_command_plugins)
73
+
74
+ def _register_builtin_and_enabled_external_plugin_commands(self):
75
+ enabled_external_plugins = (
76
+ self._plugin_config_provider.get_enabled_plugin_names()
77
+ )
78
+ loaded_command_plugins = load_builtin_and_external_command_plugins(
79
+ enabled_external_plugins
80
+ )
81
+ register_commands_from_plugins(loaded_command_plugins)
82
+
83
+ def disable_external_command_plugins(self):
84
+ self._commands_registration_config.enable_external_command_plugins = False
85
+
86
+ def before(self, callback):
87
+ def enriched_callback(value):
88
+ self._counter_of_callbacks_invoked_before_registration.increment()
89
+ callback(value)
90
+ self.register_commands_if_ready_and_not_registered_yet()
91
+
92
+ self._counter_of_callbacks_required_before_registration.increment()
93
+ return enriched_callback
94
+
95
+ def after(self, callback):
96
+ def delayed_callback(value):
97
+ self._callbacks_after_registration.append(lambda: callback(value))
98
+
99
+ return delayed_callback
100
+
101
+ def reset_running_instance_registration_state(self):
102
+ self._commands_already_registered = False
103
+ self._counter_of_callbacks_invoked_before_registration.set(0)
104
+ self._callbacks_after_registration.clear()
105
+ self._commands_registration_config.enable_external_command_plugins = True
@@ -0,0 +1,26 @@
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 logging import Logger
16
+ from typing import Callable
17
+
18
+ from snowflake.cli.api.cli_global_context import cli_context
19
+
20
+
21
+ def exception_logging(logger: Logger) -> Callable[[str, Exception], None]:
22
+ def log_error(msg: str, exception: Exception) -> None:
23
+ exc_info = exception if cli_context.enable_tracebacks else None
24
+ logger.error(msg=msg, exc_info=exc_info)
25
+
26
+ return log_error
@@ -0,0 +1,48 @@
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 threading
18
+ from typing import Callable, Generic, TypeVar
19
+
20
+ T = TypeVar("T")
21
+
22
+
23
+ class ThreadsafeValue(Generic[T]):
24
+ def __init__(self, value: T):
25
+ self._value = value
26
+ self._lock = threading.Lock()
27
+
28
+ def set(self, new_value: T) -> T: # noqa: A003
29
+ return self.transform(lambda _: new_value)
30
+
31
+ def transform(self, f: Callable[[T], T]) -> T:
32
+ with self._lock:
33
+ new_value = f(self._value)
34
+ self._value = new_value
35
+ return new_value
36
+
37
+ @property
38
+ def value(self) -> T:
39
+ with self._lock:
40
+ return self._value
41
+
42
+
43
+ class ThreadsafeCounter(ThreadsafeValue[int]):
44
+ def increment(self, d=1) -> int:
45
+ return self.transform(lambda v: v + d)
46
+
47
+ def decrement(self, d=1) -> int:
48
+ return self.increment(-d)