snowflake-cli 3.2.2__py3-none-any.whl → 3.4.1__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.
- snowflake/cli/__about__.py +1 -1
- snowflake/cli/_app/__main__.py +2 -2
- snowflake/cli/_app/cli_app.py +224 -192
- snowflake/cli/_app/commands_registration/commands_registration_with_callbacks.py +1 -27
- snowflake/cli/_app/constants.py +4 -0
- snowflake/cli/_app/snow_connector.py +12 -0
- snowflake/cli/_app/telemetry.py +10 -3
- snowflake/cli/_plugins/connection/util.py +12 -19
- snowflake/cli/_plugins/cortex/commands.py +2 -4
- snowflake/cli/_plugins/git/manager.py +1 -1
- snowflake/cli/_plugins/helpers/commands.py +207 -1
- snowflake/cli/_plugins/nativeapp/artifacts.py +16 -628
- snowflake/cli/_plugins/nativeapp/bundle_context.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/compiler.py +42 -20
- snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +9 -2
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +6 -3
- snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +44 -34
- snowflake/cli/_plugins/nativeapp/commands.py +113 -21
- snowflake/cli/_plugins/nativeapp/constants.py +5 -0
- snowflake/cli/_plugins/nativeapp/entities/application.py +226 -296
- snowflake/cli/_plugins/nativeapp/entities/application_package.py +911 -141
- snowflake/cli/_plugins/nativeapp/entities/application_package_child_interface.py +43 -0
- snowflake/cli/_plugins/nativeapp/feature_flags.py +5 -1
- snowflake/cli/_plugins/nativeapp/release_channel/__init__.py +13 -0
- snowflake/cli/_plugins/nativeapp/release_channel/commands.py +246 -0
- snowflake/cli/_plugins/nativeapp/release_directive/__init__.py +13 -0
- snowflake/cli/_plugins/nativeapp/release_directive/commands.py +243 -0
- snowflake/cli/_plugins/nativeapp/same_account_install_method.py +9 -17
- snowflake/cli/_plugins/nativeapp/sf_facade_exceptions.py +80 -0
- snowflake/cli/_plugins/nativeapp/sf_sql_facade.py +1184 -80
- snowflake/cli/_plugins/nativeapp/utils.py +11 -0
- snowflake/cli/_plugins/nativeapp/v2_conversions/compat.py +7 -3
- snowflake/cli/_plugins/nativeapp/version/commands.py +32 -5
- snowflake/cli/_plugins/notebook/commands.py +55 -2
- snowflake/cli/_plugins/notebook/exceptions.py +1 -1
- snowflake/cli/_plugins/notebook/manager.py +7 -5
- snowflake/cli/_plugins/notebook/notebook_entity.py +120 -0
- snowflake/cli/_plugins/notebook/notebook_entity_model.py +42 -0
- snowflake/cli/_plugins/notebook/notebook_project_paths.py +15 -0
- snowflake/cli/_plugins/notebook/types.py +3 -0
- snowflake/cli/_plugins/snowpark/commands.py +48 -30
- snowflake/cli/_plugins/snowpark/common.py +47 -2
- snowflake/cli/_plugins/snowpark/snowpark_entity.py +247 -4
- snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +18 -30
- snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +156 -23
- snowflake/cli/_plugins/snowpark/zipper.py +33 -1
- snowflake/cli/_plugins/spcs/common.py +129 -0
- snowflake/cli/_plugins/spcs/services/commands.py +131 -14
- snowflake/cli/_plugins/spcs/services/manager.py +169 -1
- snowflake/cli/_plugins/stage/commands.py +2 -1
- snowflake/cli/_plugins/stage/diff.py +60 -39
- snowflake/cli/_plugins/stage/manager.py +34 -13
- snowflake/cli/_plugins/stage/utils.py +1 -1
- snowflake/cli/_plugins/streamlit/commands.py +10 -1
- snowflake/cli/_plugins/streamlit/manager.py +70 -22
- snowflake/cli/_plugins/streamlit/streamlit_entity.py +131 -1
- snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +14 -24
- snowflake/cli/_plugins/streamlit/streamlit_project_paths.py +30 -0
- snowflake/cli/_plugins/workspace/commands.py +6 -5
- snowflake/cli/_plugins/workspace/manager.py +9 -5
- snowflake/cli/api/artifacts/__init__.py +13 -0
- snowflake/cli/api/artifacts/bundle_map.py +500 -0
- snowflake/cli/api/artifacts/common.py +78 -0
- snowflake/cli/api/artifacts/utils.py +82 -0
- snowflake/cli/api/cli_global_context.py +36 -2
- snowflake/cli/api/commands/flags.py +10 -4
- snowflake/cli/api/commands/utils.py +28 -2
- snowflake/cli/api/config.py +6 -2
- snowflake/cli/api/connections.py +12 -1
- snowflake/cli/api/constants.py +10 -1
- snowflake/cli/api/entities/common.py +81 -14
- snowflake/cli/api/entities/resolver.py +160 -0
- snowflake/cli/api/entities/utils.py +65 -23
- snowflake/cli/api/errno.py +63 -3
- snowflake/cli/api/feature_flags.py +19 -4
- snowflake/cli/api/metrics.py +21 -27
- snowflake/cli/api/project/definition_conversion.py +4 -4
- snowflake/cli/api/project/project_paths.py +28 -0
- snowflake/cli/api/project/schemas/entities/common.py +130 -1
- snowflake/cli/api/project/schemas/entities/entities.py +4 -0
- snowflake/cli/api/project/schemas/project_definition.py +54 -6
- snowflake/cli/api/project/schemas/updatable_model.py +2 -2
- snowflake/cli/api/project/schemas/v1/native_app/native_app.py +5 -7
- snowflake/cli/api/project/schemas/v1/streamlit/streamlit.py +1 -1
- snowflake/cli/api/project/util.py +45 -0
- snowflake/cli/api/secure_path.py +6 -0
- snowflake/cli/api/sql_execution.py +5 -1
- snowflake/cli/api/stage_path.py +7 -2
- snowflake/cli/api/utils/graph.py +3 -0
- snowflake/cli/api/utils/path_utils.py +24 -0
- {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/METADATA +14 -15
- {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/RECORD +96 -82
- {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/WHEEL +1 -1
- snowflake/cli/api/project/schemas/v1/native_app/path_mapping.py +0 -65
- {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/entry_points.txt +0 -0
- {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/licenses/LICENSE +0 -0
snowflake/cli/__about__.py
CHANGED
snowflake/cli/_app/__main__.py
CHANGED
|
@@ -16,11 +16,11 @@ from __future__ import annotations
|
|
|
16
16
|
|
|
17
17
|
import sys
|
|
18
18
|
|
|
19
|
-
from snowflake.cli._app.cli_app import
|
|
19
|
+
from snowflake.cli._app.cli_app import CliAppFactory
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def main(*args):
|
|
23
|
-
app =
|
|
23
|
+
app = CliAppFactory().create_or_get_app()
|
|
24
24
|
app(*args)
|
|
25
25
|
|
|
26
26
|
|
snowflake/cli/_app/cli_app.py
CHANGED
|
@@ -18,13 +18,12 @@ import logging
|
|
|
18
18
|
import os
|
|
19
19
|
import platform
|
|
20
20
|
import sys
|
|
21
|
-
from dataclasses import dataclass
|
|
22
21
|
from pathlib import Path
|
|
23
22
|
from typing import Optional
|
|
24
23
|
|
|
25
24
|
import click
|
|
26
25
|
import typer
|
|
27
|
-
from click import Context
|
|
26
|
+
from click import Context as ClickContext
|
|
28
27
|
from snowflake.cli import __about__
|
|
29
28
|
from snowflake.cli._app.api_impl.plugin.plugin_config_provider_impl import (
|
|
30
29
|
PluginConfigProviderImpl,
|
|
@@ -44,7 +43,7 @@ from snowflake.cli._app.version_check import (
|
|
|
44
43
|
show_new_version_banner_callback,
|
|
45
44
|
)
|
|
46
45
|
from snowflake.cli.api import Api, api_provider
|
|
47
|
-
from snowflake.cli.api.config import config_init
|
|
46
|
+
from snowflake.cli.api.config import config_init, get_feature_flags_section
|
|
48
47
|
from snowflake.cli.api.output.formats import OutputFormat
|
|
49
48
|
from snowflake.cli.api.output.types import CollectionResult
|
|
50
49
|
from snowflake.cli.api.secure_path import SecurePath
|
|
@@ -52,25 +51,6 @@ from snowflake.connector.config_manager import CONFIG_MANAGER
|
|
|
52
51
|
|
|
53
52
|
log = logging.getLogger(__name__)
|
|
54
53
|
|
|
55
|
-
_api = Api(plugin_config_provider=PluginConfigProviderImpl())
|
|
56
|
-
api_provider.register_api(_api)
|
|
57
|
-
|
|
58
|
-
_commands_registration = CommandsRegistrationWithCallbacks(_api.plugin_config_provider)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
@dataclass
|
|
62
|
-
class AppContextHolder:
|
|
63
|
-
# needed to access the context from tests
|
|
64
|
-
app_context: Optional[Context] = None
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
app_context_holder = AppContextHolder()
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def _exit_with_cleanup():
|
|
71
|
-
_commands_registration.reset_running_instance_registration_state()
|
|
72
|
-
raise typer.Exit()
|
|
73
|
-
|
|
74
54
|
|
|
75
55
|
def _do_not_execute_on_completion(callback):
|
|
76
56
|
def enriched_callback(value):
|
|
@@ -81,175 +61,227 @@ def _do_not_execute_on_completion(callback):
|
|
|
81
61
|
return enriched_callback
|
|
82
62
|
|
|
83
63
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
app_context_holder.app_context = click.get_current_context()
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@_commands_registration.before
|
|
94
|
-
def _config_init_callback(configuration_file: Optional[Path]):
|
|
95
|
-
config_init(configuration_file)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
@_commands_registration.before
|
|
99
|
-
def _disable_external_command_plugins_callback(value: bool):
|
|
100
|
-
if value:
|
|
101
|
-
_commands_registration.disable_external_command_plugins()
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
@_do_not_execute_on_completion
|
|
105
|
-
@_commands_registration.after
|
|
106
|
-
def _docs_callback(value: bool):
|
|
107
|
-
if value:
|
|
108
|
-
ctx = click.get_current_context()
|
|
109
|
-
generate_docs(SecurePath("gen_docs"), ctx.command)
|
|
110
|
-
_exit_with_cleanup()
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
@_do_not_execute_on_completion
|
|
114
|
-
@_commands_registration.after
|
|
115
|
-
def _commands_structure_callback(value: bool):
|
|
116
|
-
if value:
|
|
117
|
-
ctx = click.get_current_context()
|
|
118
|
-
generate_commands_structure(ctx.command).print_node()
|
|
119
|
-
_exit_with_cleanup()
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
@_do_not_execute_on_completion
|
|
123
|
-
def _version_callback(value: bool):
|
|
124
|
-
if value:
|
|
125
|
-
print_result(MessageResult(f"Snowflake CLI version: {__about__.VERSION}"))
|
|
126
|
-
_exit_with_cleanup()
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
from snowflake.cli.api.config import get_feature_flags_section
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
@_do_not_execute_on_completion
|
|
133
|
-
def _info_callback(value: bool):
|
|
134
|
-
if value:
|
|
135
|
-
result = CollectionResult(
|
|
136
|
-
[
|
|
137
|
-
{"key": "version", "value": __about__.VERSION},
|
|
138
|
-
{
|
|
139
|
-
"key": "default_config_file_path",
|
|
140
|
-
"value": str(CONFIG_MANAGER.file_path),
|
|
141
|
-
},
|
|
142
|
-
{"key": "python_version", "value": sys.version},
|
|
143
|
-
{"key": "system_info", "value": platform.platform()},
|
|
144
|
-
{"key": "feature_flags", "value": get_feature_flags_section()},
|
|
145
|
-
{"key": "SNOWFLAKE_HOME", "value": os.getenv("SNOWFLAKE_HOME")},
|
|
146
|
-
],
|
|
64
|
+
class CliAppFactory:
|
|
65
|
+
def __init__(self):
|
|
66
|
+
api = Api(plugin_config_provider=PluginConfigProviderImpl())
|
|
67
|
+
self._api = api
|
|
68
|
+
self._commands_registration = CommandsRegistrationWithCallbacks(
|
|
69
|
+
api.plugin_config_provider
|
|
147
70
|
)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
def
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
71
|
+
api_provider.register_api(api)
|
|
72
|
+
self._app: Optional[SnowCliMainTyper] = None
|
|
73
|
+
self._click_context: Optional[ClickContext] = None
|
|
74
|
+
|
|
75
|
+
def _exit_with_cleanup(self):
|
|
76
|
+
self._commands_registration.reset_running_instance_registration_state()
|
|
77
|
+
raise typer.Exit()
|
|
78
|
+
|
|
79
|
+
def _commands_registration_callback(self):
|
|
80
|
+
def callback(value: bool):
|
|
81
|
+
self._click_context = click.get_current_context()
|
|
82
|
+
if value:
|
|
83
|
+
self._commands_registration.register_commands_from_plugins()
|
|
84
|
+
# required to make the tests working
|
|
85
|
+
# because a single test can execute multiple commands using always the same "app" instance
|
|
86
|
+
self._commands_registration.reset_running_instance_registration_state()
|
|
87
|
+
|
|
88
|
+
return callback
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
def _config_init_callback():
|
|
92
|
+
def callback(configuration_file: Optional[Path]):
|
|
93
|
+
config_init(configuration_file)
|
|
94
|
+
|
|
95
|
+
return callback
|
|
96
|
+
|
|
97
|
+
def _disable_external_command_plugins_callback(self):
|
|
98
|
+
def callback(value: bool):
|
|
99
|
+
if value:
|
|
100
|
+
self._commands_registration.disable_external_command_plugins()
|
|
101
|
+
|
|
102
|
+
return callback
|
|
103
|
+
|
|
104
|
+
def _docs_callback(self):
|
|
105
|
+
@_do_not_execute_on_completion
|
|
106
|
+
@self._commands_registration.after
|
|
107
|
+
def callback(value: bool):
|
|
108
|
+
if value:
|
|
109
|
+
ctx = click.get_current_context()
|
|
110
|
+
generate_docs(SecurePath("gen_docs"), ctx.command)
|
|
111
|
+
self._exit_with_cleanup()
|
|
112
|
+
|
|
113
|
+
return callback
|
|
114
|
+
|
|
115
|
+
def _help_callback(self):
|
|
116
|
+
@_do_not_execute_on_completion
|
|
117
|
+
@self._commands_registration.after
|
|
118
|
+
def callback(value: bool):
|
|
119
|
+
if value:
|
|
120
|
+
ctx = click.get_current_context()
|
|
121
|
+
typer.echo(ctx.get_help())
|
|
122
|
+
self._exit_with_cleanup()
|
|
123
|
+
|
|
124
|
+
return callback
|
|
125
|
+
|
|
126
|
+
def _commands_structure_callback(self):
|
|
127
|
+
@_do_not_execute_on_completion
|
|
128
|
+
@self._commands_registration.after
|
|
129
|
+
def callback(value: bool):
|
|
130
|
+
if value:
|
|
131
|
+
ctx = click.get_current_context()
|
|
132
|
+
generate_commands_structure(ctx.command).print_node()
|
|
133
|
+
self._exit_with_cleanup()
|
|
134
|
+
|
|
135
|
+
return callback
|
|
136
|
+
|
|
137
|
+
def _version_callback(self):
|
|
138
|
+
@_do_not_execute_on_completion
|
|
139
|
+
def callback(value: bool):
|
|
140
|
+
if value:
|
|
141
|
+
print_result(
|
|
142
|
+
MessageResult(f"Snowflake CLI version: {__about__.VERSION}")
|
|
143
|
+
)
|
|
144
|
+
self._exit_with_cleanup()
|
|
145
|
+
|
|
146
|
+
return callback
|
|
147
|
+
|
|
148
|
+
def _info_callback(self):
|
|
149
|
+
@_do_not_execute_on_completion
|
|
150
|
+
def callback(value: bool):
|
|
151
|
+
if value:
|
|
152
|
+
result = CollectionResult(
|
|
153
|
+
[
|
|
154
|
+
{"key": "version", "value": __about__.VERSION},
|
|
155
|
+
{
|
|
156
|
+
"key": "default_config_file_path",
|
|
157
|
+
"value": str(CONFIG_MANAGER.file_path),
|
|
158
|
+
},
|
|
159
|
+
{"key": "python_version", "value": sys.version},
|
|
160
|
+
{"key": "system_info", "value": platform.platform()},
|
|
161
|
+
{"key": "feature_flags", "value": get_feature_flags_section()},
|
|
162
|
+
{"key": "SNOWFLAKE_HOME", "value": os.getenv("SNOWFLAKE_HOME")},
|
|
163
|
+
],
|
|
164
|
+
)
|
|
165
|
+
print_result(result, output_format=OutputFormat.JSON)
|
|
166
|
+
self._exit_with_cleanup()
|
|
167
|
+
|
|
168
|
+
return callback
|
|
169
|
+
|
|
170
|
+
def create_or_get_app(self) -> SnowCliMainTyper:
|
|
171
|
+
if self._app:
|
|
172
|
+
return self._app
|
|
173
|
+
|
|
174
|
+
app = SnowCliMainTyper()
|
|
175
|
+
new_version_msg = get_new_version_msg()
|
|
176
|
+
|
|
177
|
+
@app.callback(
|
|
178
|
+
invoke_without_command=True,
|
|
179
|
+
epilog=new_version_msg,
|
|
180
|
+
result_callback=show_new_version_banner_callback(new_version_msg),
|
|
181
|
+
add_help_option=False, # custom_help option added below
|
|
182
|
+
help=f"Snowflake CLI tool for developers [v{__about__.VERSION}]",
|
|
253
183
|
)
|
|
254
|
-
|
|
255
|
-
|
|
184
|
+
def default(
|
|
185
|
+
ctx: typer.Context,
|
|
186
|
+
# We need a custom help option with _help_callback called after command registration
|
|
187
|
+
# to have all commands visible in the help.
|
|
188
|
+
# This is required since click 8.1.8, when the default help option
|
|
189
|
+
# has started to being executed before our eager options, including command registration.
|
|
190
|
+
custom_help: bool = typer.Option(
|
|
191
|
+
None,
|
|
192
|
+
"--help",
|
|
193
|
+
"-h",
|
|
194
|
+
help="Show this message and exit.",
|
|
195
|
+
callback=self._help_callback,
|
|
196
|
+
is_eager=True,
|
|
197
|
+
),
|
|
198
|
+
version: bool = typer.Option(
|
|
199
|
+
None,
|
|
200
|
+
"--version",
|
|
201
|
+
help="Shows version of the Snowflake CLI",
|
|
202
|
+
callback=self._version_callback(),
|
|
203
|
+
is_eager=True,
|
|
204
|
+
),
|
|
205
|
+
docs: bool = typer.Option(
|
|
206
|
+
None,
|
|
207
|
+
"--docs",
|
|
208
|
+
hidden=True,
|
|
209
|
+
help="Generates Snowflake CLI documentation",
|
|
210
|
+
callback=self._docs_callback(),
|
|
211
|
+
is_eager=True,
|
|
212
|
+
),
|
|
213
|
+
structure: bool = typer.Option(
|
|
214
|
+
None,
|
|
215
|
+
"--structure",
|
|
216
|
+
hidden=True,
|
|
217
|
+
help="Prints Snowflake CLI structure of commands",
|
|
218
|
+
callback=self._commands_structure_callback(),
|
|
219
|
+
is_eager=True,
|
|
220
|
+
),
|
|
221
|
+
info: bool = typer.Option(
|
|
222
|
+
None,
|
|
223
|
+
"--info",
|
|
224
|
+
help="Shows information about the Snowflake CLI",
|
|
225
|
+
callback=self._info_callback(),
|
|
226
|
+
),
|
|
227
|
+
configuration_file: Path = typer.Option(
|
|
228
|
+
None,
|
|
229
|
+
"--config-file",
|
|
230
|
+
help="Specifies Snowflake CLI configuration file that should be used",
|
|
231
|
+
exists=True,
|
|
232
|
+
dir_okay=False,
|
|
233
|
+
is_eager=True,
|
|
234
|
+
callback=self._config_init_callback(),
|
|
235
|
+
),
|
|
236
|
+
pycharm_debug_library_path: str = typer.Option(
|
|
237
|
+
None,
|
|
238
|
+
"--pycharm-debug-library-path",
|
|
239
|
+
hidden=True,
|
|
240
|
+
),
|
|
241
|
+
pycharm_debug_server_host: str = typer.Option(
|
|
242
|
+
"localhost",
|
|
243
|
+
"--pycharm-debug-server-host",
|
|
244
|
+
hidden=True,
|
|
245
|
+
),
|
|
246
|
+
pycharm_debug_server_port: int = typer.Option(
|
|
247
|
+
12345,
|
|
248
|
+
"--pycharm-debug-server-port",
|
|
249
|
+
hidden=True,
|
|
250
|
+
),
|
|
251
|
+
disable_external_command_plugins: bool = typer.Option(
|
|
252
|
+
None,
|
|
253
|
+
"--disable-external-command-plugins",
|
|
254
|
+
help="Disable external command plugins",
|
|
255
|
+
callback=self._disable_external_command_plugins_callback(),
|
|
256
|
+
is_eager=True,
|
|
257
|
+
hidden=True,
|
|
258
|
+
),
|
|
259
|
+
# THIS OPTION SHOULD BE THE LAST OPTION IN THE LIST!
|
|
260
|
+
# ---
|
|
261
|
+
# This is a hidden artificial option used only to guarantee execution of commands registration.
|
|
262
|
+
# This option is also responsible for resetting registration state for test purposes.
|
|
263
|
+
commands_registration: bool = typer.Option(
|
|
264
|
+
True,
|
|
265
|
+
"--commands-registration",
|
|
266
|
+
help="Commands registration",
|
|
267
|
+
hidden=True,
|
|
268
|
+
is_eager=True,
|
|
269
|
+
callback=self._commands_registration_callback(),
|
|
270
|
+
),
|
|
271
|
+
) -> None:
|
|
272
|
+
"""
|
|
273
|
+
Snowflake CLI tool for developers.
|
|
274
|
+
"""
|
|
275
|
+
if not ctx.invoked_subcommand:
|
|
276
|
+
typer.echo(ctx.get_help())
|
|
277
|
+
setup_pycharm_remote_debugger_if_provided(
|
|
278
|
+
pycharm_debug_library_path=pycharm_debug_library_path,
|
|
279
|
+
pycharm_debug_server_host=pycharm_debug_server_host,
|
|
280
|
+
pycharm_debug_server_port=pycharm_debug_server_port,
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
self._app = app
|
|
284
|
+
return app
|
|
285
|
+
|
|
286
|
+
def get_click_context(self):
|
|
287
|
+
return self._click_context
|
|
@@ -21,7 +21,6 @@ from snowflake.cli._app.commands_registration.command_plugins_loader import (
|
|
|
21
21
|
load_builtin_and_external_command_plugins,
|
|
22
22
|
load_only_builtin_command_plugins,
|
|
23
23
|
)
|
|
24
|
-
from snowflake.cli._app.commands_registration.threadsafe import ThreadsafeCounter
|
|
25
24
|
from snowflake.cli._app.commands_registration.typer_registration import (
|
|
26
25
|
register_commands_from_plugins,
|
|
27
26
|
)
|
|
@@ -36,27 +35,13 @@ class CommandRegistrationConfig:
|
|
|
36
35
|
class CommandsRegistrationWithCallbacks:
|
|
37
36
|
def __init__(self, plugin_config_provider: PluginConfigProvider):
|
|
38
37
|
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
38
|
self._callbacks_after_registration: List[Callable[[], None]] = []
|
|
46
39
|
self._commands_registration_config: CommandRegistrationConfig = (
|
|
47
40
|
CommandRegistrationConfig(enable_external_command_plugins=True)
|
|
48
41
|
)
|
|
49
42
|
self._commands_already_registered: bool = False
|
|
50
43
|
|
|
51
|
-
def
|
|
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:
|
|
44
|
+
def register_commands_from_plugins(self) -> None:
|
|
60
45
|
if self._commands_registration_config.enable_external_command_plugins:
|
|
61
46
|
self._register_builtin_and_enabled_external_plugin_commands()
|
|
62
47
|
else:
|
|
@@ -83,15 +68,6 @@ class CommandsRegistrationWithCallbacks:
|
|
|
83
68
|
def disable_external_command_plugins(self):
|
|
84
69
|
self._commands_registration_config.enable_external_command_plugins = False
|
|
85
70
|
|
|
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
71
|
def after(self, callback):
|
|
96
72
|
def delayed_callback(value):
|
|
97
73
|
self._callbacks_after_registration.append(lambda: callback(value))
|
|
@@ -99,7 +75,5 @@ class CommandsRegistrationWithCallbacks:
|
|
|
99
75
|
return delayed_callback
|
|
100
76
|
|
|
101
77
|
def reset_running_instance_registration_state(self):
|
|
102
|
-
self._commands_already_registered = False
|
|
103
|
-
self._counter_of_callbacks_invoked_before_registration.set(0)
|
|
104
78
|
self._callbacks_after_registration.clear()
|
|
105
79
|
self._commands_registration_config.enable_external_command_plugins = True
|
snowflake/cli/_app/constants.py
CHANGED
|
@@ -17,3 +17,7 @@ from __future__ import annotations
|
|
|
17
17
|
from typing import Literal
|
|
18
18
|
|
|
19
19
|
PARAM_APPLICATION_NAME: Literal["snowcli"] = "snowcli"
|
|
20
|
+
|
|
21
|
+
# This is also defined on server side. Changing this parameter would require
|
|
22
|
+
# a change in https://github.com/snowflakedb/snowflake
|
|
23
|
+
INTERNAL_APPLICATION_NAME: Literal["SNOWFLAKE_CLI"] = "SNOWFLAKE_CLI"
|
|
@@ -21,7 +21,9 @@ from typing import Dict, Optional
|
|
|
21
21
|
|
|
22
22
|
import snowflake.connector
|
|
23
23
|
from click.exceptions import ClickException
|
|
24
|
+
from snowflake.cli.__about__ import VERSION
|
|
24
25
|
from snowflake.cli._app.constants import (
|
|
26
|
+
INTERNAL_APPLICATION_NAME,
|
|
25
27
|
PARAM_APPLICATION_NAME,
|
|
26
28
|
)
|
|
27
29
|
from snowflake.cli._app.secret import SecretType
|
|
@@ -35,6 +37,7 @@ from snowflake.cli.api.exceptions import (
|
|
|
35
37
|
InvalidConnectionConfiguration,
|
|
36
38
|
SnowflakeConnectionError,
|
|
37
39
|
)
|
|
40
|
+
from snowflake.cli.api.feature_flags import FeatureFlag
|
|
38
41
|
from snowflake.cli.api.secure_path import SecurePath
|
|
39
42
|
from snowflake.connector import SnowflakeConnection
|
|
40
43
|
from snowflake.connector.errors import DatabaseError, ForbiddenError
|
|
@@ -150,6 +153,8 @@ def connect_to_snowflake(
|
|
|
150
153
|
|
|
151
154
|
_update_connection_application_name(connection_parameters)
|
|
152
155
|
|
|
156
|
+
_update_internal_application_info(connection_parameters)
|
|
157
|
+
|
|
153
158
|
try:
|
|
154
159
|
# Whatever output is generated when creating connection,
|
|
155
160
|
# we don't want it in our output. This is particularly important
|
|
@@ -238,6 +243,13 @@ def _update_connection_application_name(connection_parameters: Dict):
|
|
|
238
243
|
connection_parameters.update(connection_application_params)
|
|
239
244
|
|
|
240
245
|
|
|
246
|
+
def _update_internal_application_info(connection_parameters: Dict):
|
|
247
|
+
"""Update internal application data if ENABLE_SEPARATE_AUTHENTICATION_POLICY_ID is enabled."""
|
|
248
|
+
if FeatureFlag.ENABLE_SEPARATE_AUTHENTICATION_POLICY_ID.is_enabled():
|
|
249
|
+
connection_parameters["internal_application_name"] = INTERNAL_APPLICATION_NAME
|
|
250
|
+
connection_parameters["internal_application_version"] = VERSION
|
|
251
|
+
|
|
252
|
+
|
|
241
253
|
def _load_pem_from_file(private_key_file: str) -> SecretType:
|
|
242
254
|
with SecurePath(private_key_file).open(
|
|
243
255
|
"rb", read_file_limit_mb=DEFAULT_SIZE_LIMIT_MB
|
snowflake/cli/_app/telemetry.py
CHANGED
|
@@ -67,6 +67,10 @@ class CLITelemetryField(Enum):
|
|
|
67
67
|
CONFIG_FEATURE_FLAGS = "config_feature_flags"
|
|
68
68
|
# Metrics
|
|
69
69
|
COUNTERS = "counters"
|
|
70
|
+
SPANS = "spans"
|
|
71
|
+
COMPLETED_SPANS = "completed_spans"
|
|
72
|
+
NUM_SPANS_PAST_DEPTH_LIMIT = "num_spans_past_depth_limit"
|
|
73
|
+
NUM_SPANS_PAST_TOTAL_LIMIT = "num_spans_past_total_limit"
|
|
70
74
|
# Information
|
|
71
75
|
EVENT = "event"
|
|
72
76
|
ERROR_MSG = "error_msg"
|
|
@@ -129,9 +133,12 @@ def _get_command_metrics() -> TelemetryDict:
|
|
|
129
133
|
cli_context = get_cli_context()
|
|
130
134
|
|
|
131
135
|
return {
|
|
132
|
-
CLITelemetryField.COUNTERS:
|
|
133
|
-
|
|
134
|
-
|
|
136
|
+
CLITelemetryField.COUNTERS: cli_context.metrics.counters,
|
|
137
|
+
CLITelemetryField.SPANS: {
|
|
138
|
+
CLITelemetryField.COMPLETED_SPANS.value: cli_context.metrics.completed_spans,
|
|
139
|
+
CLITelemetryField.NUM_SPANS_PAST_DEPTH_LIMIT.value: cli_context.metrics.num_spans_past_depth_limit,
|
|
140
|
+
CLITelemetryField.NUM_SPANS_PAST_TOTAL_LIMIT.value: cli_context.metrics.num_spans_past_total_limit,
|
|
141
|
+
},
|
|
135
142
|
}
|
|
136
143
|
|
|
137
144
|
|
|
@@ -19,7 +19,6 @@ import logging
|
|
|
19
19
|
import os
|
|
20
20
|
from enum import Enum
|
|
21
21
|
from functools import lru_cache
|
|
22
|
-
from textwrap import dedent
|
|
23
22
|
from typing import Any, Dict, Optional
|
|
24
23
|
|
|
25
24
|
from click.exceptions import ClickException
|
|
@@ -57,11 +56,12 @@ class UIParameter(Enum):
|
|
|
57
56
|
NA_ENFORCE_MANDATORY_FILTERS = (
|
|
58
57
|
"ENFORCE_MANDATORY_FILTERS_FOR_SAME_ACCOUNT_INSTALLATION"
|
|
59
58
|
)
|
|
59
|
+
NA_FEATURE_RELEASE_CHANNELS = "FEATURE_RELEASE_CHANNELS"
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
def get_ui_parameter(
|
|
63
63
|
conn: SnowflakeConnection, parameter: UIParameter, default: Any
|
|
64
|
-
) ->
|
|
64
|
+
) -> Any:
|
|
65
65
|
"""
|
|
66
66
|
Returns the value of a single UI parameter.
|
|
67
67
|
If the parameter is not found, the default value is returned.
|
|
@@ -77,21 +77,19 @@ def get_ui_parameters(conn: SnowflakeConnection) -> Dict[UIParameter, Any]:
|
|
|
77
77
|
Returns the UI parameters from the SYSTEM$BOOTSTRAP_DATA_REQUEST function
|
|
78
78
|
"""
|
|
79
79
|
|
|
80
|
-
parameters_to_fetch =
|
|
80
|
+
parameters_to_fetch = [param.value for param in UIParameter]
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
path => 'clientParamsInfo'
|
|
87
|
-
)) where value['name'] in ('{"', '".join(parameters_to_fetch)}');
|
|
88
|
-
"""
|
|
89
|
-
)
|
|
82
|
+
# Parsing of the Json and the filtering is happening here in Snowflake CLI
|
|
83
|
+
# in order to avoid requiring a warehouse in Snowflake
|
|
84
|
+
query = "call system$bootstrap_data_request('CLIENT_PARAMS_INFO')"
|
|
85
|
+
*_, cursor = conn.execute_string(query)
|
|
90
86
|
|
|
91
|
-
|
|
87
|
+
json_map = json.loads(cursor.fetchone()[0])
|
|
92
88
|
|
|
93
89
|
return {
|
|
94
|
-
UIParameter(row["
|
|
90
|
+
UIParameter(row["name"]): row["value"]
|
|
91
|
+
for row in json_map["clientParamsInfo"]
|
|
92
|
+
if row["name"] in parameters_to_fetch
|
|
95
93
|
}
|
|
96
94
|
|
|
97
95
|
|
|
@@ -103,12 +101,7 @@ def is_regionless_redirect(conn: SnowflakeConnection) -> bool:
|
|
|
103
101
|
assume it's regionless, as this is true for most production deployments.
|
|
104
102
|
"""
|
|
105
103
|
try:
|
|
106
|
-
return (
|
|
107
|
-
get_ui_parameter(
|
|
108
|
-
conn, UIParameter.NA_ENABLE_REGIONLESS_REDIRECT, "true"
|
|
109
|
-
).lower()
|
|
110
|
-
== "true"
|
|
111
|
-
)
|
|
104
|
+
return get_ui_parameter(conn, UIParameter.NA_ENABLE_REGIONLESS_REDIRECT, True)
|
|
112
105
|
except:
|
|
113
106
|
log.warning(
|
|
114
107
|
"Cannot determine regionless redirect; assuming True.", exc_info=True
|