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.
Files changed (97) hide show
  1. snowflake/cli/__about__.py +1 -1
  2. snowflake/cli/_app/__main__.py +2 -2
  3. snowflake/cli/_app/cli_app.py +224 -192
  4. snowflake/cli/_app/commands_registration/commands_registration_with_callbacks.py +1 -27
  5. snowflake/cli/_app/constants.py +4 -0
  6. snowflake/cli/_app/snow_connector.py +12 -0
  7. snowflake/cli/_app/telemetry.py +10 -3
  8. snowflake/cli/_plugins/connection/util.py +12 -19
  9. snowflake/cli/_plugins/cortex/commands.py +2 -4
  10. snowflake/cli/_plugins/git/manager.py +1 -1
  11. snowflake/cli/_plugins/helpers/commands.py +207 -1
  12. snowflake/cli/_plugins/nativeapp/artifacts.py +16 -628
  13. snowflake/cli/_plugins/nativeapp/bundle_context.py +1 -1
  14. snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +1 -1
  15. snowflake/cli/_plugins/nativeapp/codegen/compiler.py +42 -20
  16. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +9 -2
  17. snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +6 -3
  18. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +44 -34
  19. snowflake/cli/_plugins/nativeapp/commands.py +113 -21
  20. snowflake/cli/_plugins/nativeapp/constants.py +5 -0
  21. snowflake/cli/_plugins/nativeapp/entities/application.py +226 -296
  22. snowflake/cli/_plugins/nativeapp/entities/application_package.py +911 -141
  23. snowflake/cli/_plugins/nativeapp/entities/application_package_child_interface.py +43 -0
  24. snowflake/cli/_plugins/nativeapp/feature_flags.py +5 -1
  25. snowflake/cli/_plugins/nativeapp/release_channel/__init__.py +13 -0
  26. snowflake/cli/_plugins/nativeapp/release_channel/commands.py +246 -0
  27. snowflake/cli/_plugins/nativeapp/release_directive/__init__.py +13 -0
  28. snowflake/cli/_plugins/nativeapp/release_directive/commands.py +243 -0
  29. snowflake/cli/_plugins/nativeapp/same_account_install_method.py +9 -17
  30. snowflake/cli/_plugins/nativeapp/sf_facade_exceptions.py +80 -0
  31. snowflake/cli/_plugins/nativeapp/sf_sql_facade.py +1184 -80
  32. snowflake/cli/_plugins/nativeapp/utils.py +11 -0
  33. snowflake/cli/_plugins/nativeapp/v2_conversions/compat.py +7 -3
  34. snowflake/cli/_plugins/nativeapp/version/commands.py +32 -5
  35. snowflake/cli/_plugins/notebook/commands.py +55 -2
  36. snowflake/cli/_plugins/notebook/exceptions.py +1 -1
  37. snowflake/cli/_plugins/notebook/manager.py +7 -5
  38. snowflake/cli/_plugins/notebook/notebook_entity.py +120 -0
  39. snowflake/cli/_plugins/notebook/notebook_entity_model.py +42 -0
  40. snowflake/cli/_plugins/notebook/notebook_project_paths.py +15 -0
  41. snowflake/cli/_plugins/notebook/types.py +3 -0
  42. snowflake/cli/_plugins/snowpark/commands.py +48 -30
  43. snowflake/cli/_plugins/snowpark/common.py +47 -2
  44. snowflake/cli/_plugins/snowpark/snowpark_entity.py +247 -4
  45. snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +18 -30
  46. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +156 -23
  47. snowflake/cli/_plugins/snowpark/zipper.py +33 -1
  48. snowflake/cli/_plugins/spcs/common.py +129 -0
  49. snowflake/cli/_plugins/spcs/services/commands.py +131 -14
  50. snowflake/cli/_plugins/spcs/services/manager.py +169 -1
  51. snowflake/cli/_plugins/stage/commands.py +2 -1
  52. snowflake/cli/_plugins/stage/diff.py +60 -39
  53. snowflake/cli/_plugins/stage/manager.py +34 -13
  54. snowflake/cli/_plugins/stage/utils.py +1 -1
  55. snowflake/cli/_plugins/streamlit/commands.py +10 -1
  56. snowflake/cli/_plugins/streamlit/manager.py +70 -22
  57. snowflake/cli/_plugins/streamlit/streamlit_entity.py +131 -1
  58. snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +14 -24
  59. snowflake/cli/_plugins/streamlit/streamlit_project_paths.py +30 -0
  60. snowflake/cli/_plugins/workspace/commands.py +6 -5
  61. snowflake/cli/_plugins/workspace/manager.py +9 -5
  62. snowflake/cli/api/artifacts/__init__.py +13 -0
  63. snowflake/cli/api/artifacts/bundle_map.py +500 -0
  64. snowflake/cli/api/artifacts/common.py +78 -0
  65. snowflake/cli/api/artifacts/utils.py +82 -0
  66. snowflake/cli/api/cli_global_context.py +36 -2
  67. snowflake/cli/api/commands/flags.py +10 -4
  68. snowflake/cli/api/commands/utils.py +28 -2
  69. snowflake/cli/api/config.py +6 -2
  70. snowflake/cli/api/connections.py +12 -1
  71. snowflake/cli/api/constants.py +10 -1
  72. snowflake/cli/api/entities/common.py +81 -14
  73. snowflake/cli/api/entities/resolver.py +160 -0
  74. snowflake/cli/api/entities/utils.py +65 -23
  75. snowflake/cli/api/errno.py +63 -3
  76. snowflake/cli/api/feature_flags.py +19 -4
  77. snowflake/cli/api/metrics.py +21 -27
  78. snowflake/cli/api/project/definition_conversion.py +4 -4
  79. snowflake/cli/api/project/project_paths.py +28 -0
  80. snowflake/cli/api/project/schemas/entities/common.py +130 -1
  81. snowflake/cli/api/project/schemas/entities/entities.py +4 -0
  82. snowflake/cli/api/project/schemas/project_definition.py +54 -6
  83. snowflake/cli/api/project/schemas/updatable_model.py +2 -2
  84. snowflake/cli/api/project/schemas/v1/native_app/native_app.py +5 -7
  85. snowflake/cli/api/project/schemas/v1/streamlit/streamlit.py +1 -1
  86. snowflake/cli/api/project/util.py +45 -0
  87. snowflake/cli/api/secure_path.py +6 -0
  88. snowflake/cli/api/sql_execution.py +5 -1
  89. snowflake/cli/api/stage_path.py +7 -2
  90. snowflake/cli/api/utils/graph.py +3 -0
  91. snowflake/cli/api/utils/path_utils.py +24 -0
  92. {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/METADATA +14 -15
  93. {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/RECORD +96 -82
  94. {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/WHEEL +1 -1
  95. snowflake/cli/api/project/schemas/v1/native_app/path_mapping.py +0 -65
  96. {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/entry_points.txt +0 -0
  97. {snowflake_cli-3.2.2.dist-info → snowflake_cli-3.4.1.dist-info}/licenses/LICENSE +0 -0
@@ -96,16 +96,14 @@ def search(
96
96
  "Cortex Search uses Snowflake Python API that currently does not support your Python version"
97
97
  )
98
98
 
99
- from snowflake.core import Root
100
-
101
99
  if not columns:
102
100
  columns = []
103
101
 
104
102
  conn = get_cli_context().connection
103
+ root = get_cli_context().snow_api_root
105
104
 
106
105
  search_service = (
107
- Root(conn)
108
- .databases[conn.database]
106
+ root.databases[conn.database]
109
107
  .schemas[conn.schema]
110
108
  .cortex_search_services[service]
111
109
  )
@@ -116,7 +116,7 @@ class GitManager(StageManager):
116
116
  return f"{'/'.join(path_parts[ONLY_STAGE])}/"
117
117
 
118
118
  @staticmethod
119
- def _stage_path_part_factory(stage_path: str) -> StagePathParts:
119
+ def stage_path_parts_from_str(stage_path: str) -> StagePathParts:
120
120
  stage_path = StageManager.get_standard_stage_prefix(stage_path)
121
121
  if stage_path.startswith(USER_STAGE_PREFIX):
122
122
  return UserStagePathParts(stage_path)
@@ -14,17 +14,30 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
+ import logging
18
+ from pathlib import Path
19
+ from typing import Any, List, Optional
20
+
17
21
  import typer
18
22
  import yaml
19
23
  from click import ClickException
20
24
  from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
21
- from snowflake.cli.api.output.types import MessageResult
25
+ from snowflake.cli.api.config import (
26
+ ConnectionConfig,
27
+ add_connection_to_proper_file,
28
+ get_all_connections,
29
+ set_config_value,
30
+ )
31
+ from snowflake.cli.api.console import cli_console
32
+ from snowflake.cli.api.output.types import CommandResult, MessageResult
22
33
  from snowflake.cli.api.project.definition_conversion import (
23
34
  convert_project_definition_to_v2,
24
35
  )
25
36
  from snowflake.cli.api.project.definition_manager import DefinitionManager
26
37
  from snowflake.cli.api.secure_path import SecurePath
27
38
 
39
+ log = logging.getLogger(__name__)
40
+
28
41
  app = SnowTyperFactory(
29
42
  name="helpers",
30
43
  help="Helper commands.",
@@ -88,3 +101,196 @@ def v1_to_v2(
88
101
  width=float("inf"), # Don't break lines
89
102
  )
90
103
  return MessageResult("Project definition migrated to version 2.")
104
+
105
+
106
+ @app.command(name="import-snowsql-connections", requires_connection=False)
107
+ def import_snowsql_connections(
108
+ custom_snowsql_config_files: Optional[List[Path]] = typer.Option(
109
+ None,
110
+ "--snowsql-config-file",
111
+ help="Specifies file paths to custom SnowSQL configuration. The option can be used multiple times to specify more than 1 file.",
112
+ dir_okay=False,
113
+ exists=True,
114
+ ),
115
+ default_cli_connection_name: str = typer.Option(
116
+ "default",
117
+ "--default-connection-name",
118
+ help="Specifies the name which will be given in Snowflake CLI to the default connection imported from SnowSQL.",
119
+ ),
120
+ **options,
121
+ ) -> CommandResult:
122
+ """Import your existing connections from your SnowSQL configuration."""
123
+
124
+ snowsql_config_files: list[Path] = custom_snowsql_config_files or [
125
+ Path("/etc/snowsql.cnf"),
126
+ Path("/etc/snowflake/snowsql.cnf"),
127
+ Path("/usr/local/etc/snowsql.cnf"),
128
+ Path.home() / Path(".snowsql.cnf"),
129
+ Path.home() / Path(".snowsql/config"),
130
+ ]
131
+ snowsql_config_secure_paths: list[SecurePath] = [
132
+ SecurePath(p) for p in snowsql_config_files
133
+ ]
134
+
135
+ all_imported_connections = _read_all_connections_from_snowsql(
136
+ default_cli_connection_name, snowsql_config_secure_paths
137
+ )
138
+ _validate_and_save_connections_imported_from_snowsql(
139
+ default_cli_connection_name, all_imported_connections
140
+ )
141
+ return MessageResult(
142
+ "Connections successfully imported from SnowSQL to Snowflake CLI."
143
+ )
144
+
145
+
146
+ def _read_all_connections_from_snowsql(
147
+ default_cli_connection_name: str, snowsql_config_files: List[SecurePath]
148
+ ) -> dict[str, dict]:
149
+ import configparser
150
+
151
+ imported_default_connection: dict[str, Any] = {}
152
+ imported_named_connections: dict[str, dict] = {}
153
+
154
+ for file in snowsql_config_files:
155
+ if not file.exists():
156
+ cli_console.step(
157
+ f"SnowSQL config file [{str(file.path)}] does not exist. Skipping."
158
+ )
159
+ continue
160
+
161
+ cli_console.step(f"Trying to read connections from [{str(file.path)}].")
162
+ snowsql_config = configparser.ConfigParser()
163
+ snowsql_config.read(file.path)
164
+
165
+ if "connections" in snowsql_config and snowsql_config.items("connections"):
166
+ cli_console.step(
167
+ f"Reading SnowSQL's default connection configuration from [{str(file.path)}]"
168
+ )
169
+ snowsql_default_connection = snowsql_config.items("connections")
170
+ imported_default_connection.update(
171
+ _convert_connection_from_snowsql_config_section(
172
+ snowsql_default_connection
173
+ )
174
+ )
175
+
176
+ other_snowsql_connection_section_names = [
177
+ section_name
178
+ for section_name in snowsql_config.sections()
179
+ if section_name.startswith("connections.")
180
+ ]
181
+ for snowsql_connection_section_name in other_snowsql_connection_section_names:
182
+ cli_console.step(
183
+ f"Reading SnowSQL's connection configuration [{snowsql_connection_section_name}] from [{str(file.path)}]"
184
+ )
185
+ snowsql_named_connection = snowsql_config.items(
186
+ snowsql_connection_section_name
187
+ )
188
+ if not snowsql_named_connection:
189
+ cli_console.step(
190
+ f"Empty connection configuration [{snowsql_connection_section_name}] in [{str(file.path)}]. Skipping."
191
+ )
192
+ continue
193
+
194
+ connection_name = snowsql_connection_section_name.removeprefix(
195
+ "connections."
196
+ )
197
+ imported_named_conenction = _convert_connection_from_snowsql_config_section(
198
+ snowsql_named_connection
199
+ )
200
+ if connection_name in imported_named_connections:
201
+ imported_named_connections[connection_name].update(
202
+ imported_named_conenction
203
+ )
204
+ else:
205
+ imported_named_connections[connection_name] = imported_named_conenction
206
+
207
+ def imported_default_connection_as_named_connection():
208
+ name = _validate_imported_default_connection_name(
209
+ default_cli_connection_name, imported_named_connections
210
+ )
211
+ return {name: imported_default_connection}
212
+
213
+ named_default_connection = (
214
+ imported_default_connection_as_named_connection()
215
+ if imported_default_connection
216
+ else {}
217
+ )
218
+
219
+ return imported_named_connections | named_default_connection
220
+
221
+
222
+ def _validate_imported_default_connection_name(
223
+ name_candidate: str, other_snowsql_connections: dict[str, dict]
224
+ ) -> str:
225
+ if name_candidate in other_snowsql_connections:
226
+ new_name_candidate = typer.prompt(
227
+ f"Chosen default connection name '{name_candidate}' is already taken by other connection being imported from SnowSQL. Please choose a different name for your default connection"
228
+ )
229
+ return _validate_imported_default_connection_name(
230
+ new_name_candidate, other_snowsql_connections
231
+ )
232
+ else:
233
+ return name_candidate
234
+
235
+
236
+ def _convert_connection_from_snowsql_config_section(
237
+ snowsql_connection: list[tuple[str, Any]]
238
+ ) -> dict[str, Any]:
239
+ from ast import literal_eval
240
+
241
+ key_names_replacements = {
242
+ "accountname": "account",
243
+ "username": "user",
244
+ "databasename": "database",
245
+ "dbname": "database",
246
+ "schemaname": "schema",
247
+ "warehousename": "warehouse",
248
+ "rolename": "role",
249
+ "private_key_path": "private_key_file",
250
+ }
251
+
252
+ def parse_value(value: Any):
253
+ try:
254
+ parsed_value = literal_eval(value)
255
+ except Exception:
256
+ parsed_value = value
257
+ return parsed_value
258
+
259
+ cli_connection: dict[str, Any] = {}
260
+ for key, value in snowsql_connection:
261
+ cli_key = key_names_replacements.get(key, key)
262
+ cli_value = parse_value(value)
263
+ cli_connection[cli_key] = cli_value
264
+ return cli_connection
265
+
266
+
267
+ def _validate_and_save_connections_imported_from_snowsql(
268
+ default_cli_connection_name: str, all_imported_connections: dict[str, Any]
269
+ ):
270
+ existing_cli_connection_names: set[str] = set(get_all_connections().keys())
271
+ imported_connections_to_save: dict[str, Any] = {}
272
+ for (
273
+ imported_connection_name,
274
+ imported_connection,
275
+ ) in all_imported_connections.items():
276
+ if imported_connection_name in existing_cli_connection_names:
277
+ override_cli_connection = typer.confirm(
278
+ f"Connection '{imported_connection_name}' already exists in Snowflake CLI, do you want to use SnowSQL definition and override existing connection in Snowflake CLI?"
279
+ )
280
+ if not override_cli_connection:
281
+ continue
282
+ imported_connections_to_save[imported_connection_name] = imported_connection
283
+
284
+ for name, connection in imported_connections_to_save.items():
285
+ cli_console.step(f"Saving [{name}] connection in Snowflake CLI's config.")
286
+ add_connection_to_proper_file(name, ConnectionConfig.from_dict(connection))
287
+
288
+ if default_cli_connection_name in imported_connections_to_save:
289
+ cli_console.step(
290
+ f"Setting [{default_cli_connection_name}] connection as Snowflake CLI's default connection."
291
+ )
292
+ set_config_value(
293
+ section=None,
294
+ key="default_connection_name",
295
+ value=default_cli_connection_name,
296
+ )