snowflake-cli 3.11.0__py3-none-any.whl → 3.13.0__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/cli_app.py +43 -1
- snowflake/cli/_app/commands_registration/builtin_plugins.py +1 -1
- snowflake/cli/_app/commands_registration/command_plugins_loader.py +14 -1
- snowflake/cli/_app/printing.py +153 -19
- snowflake/cli/_app/telemetry.py +25 -10
- snowflake/cli/_plugins/auth/__init__.py +0 -2
- snowflake/cli/_plugins/connection/commands.py +1 -78
- snowflake/cli/_plugins/dbt/commands.py +44 -19
- snowflake/cli/_plugins/dbt/constants.py +1 -1
- snowflake/cli/_plugins/dbt/manager.py +252 -47
- snowflake/cli/_plugins/dcm/commands.py +65 -90
- snowflake/cli/_plugins/dcm/manager.py +137 -50
- snowflake/cli/_plugins/logs/commands.py +7 -0
- snowflake/cli/_plugins/logs/manager.py +21 -1
- snowflake/cli/_plugins/nativeapp/entities/application_package.py +4 -1
- snowflake/cli/_plugins/nativeapp/sf_sql_facade.py +3 -1
- snowflake/cli/_plugins/object/manager.py +1 -0
- snowflake/cli/_plugins/snowpark/common.py +1 -0
- snowflake/cli/_plugins/snowpark/package/anaconda_packages.py +29 -5
- snowflake/cli/_plugins/snowpark/package_utils.py +44 -3
- snowflake/cli/_plugins/spcs/services/commands.py +19 -1
- snowflake/cli/_plugins/spcs/services/manager.py +17 -4
- snowflake/cli/_plugins/spcs/services/service_entity_model.py +5 -0
- snowflake/cli/_plugins/sql/lexer/types.py +1 -0
- snowflake/cli/_plugins/sql/repl.py +100 -26
- snowflake/cli/_plugins/sql/repl_commands.py +607 -0
- snowflake/cli/_plugins/sql/statement_reader.py +44 -20
- snowflake/cli/_plugins/streamlit/streamlit_entity.py +28 -2
- snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +24 -4
- snowflake/cli/api/artifacts/bundle_map.py +32 -2
- snowflake/cli/api/artifacts/regex_resolver.py +54 -0
- snowflake/cli/api/artifacts/upload.py +5 -1
- snowflake/cli/api/artifacts/utils.py +12 -1
- snowflake/cli/api/cli_global_context.py +7 -0
- snowflake/cli/api/commands/decorators.py +7 -0
- snowflake/cli/api/commands/flags.py +24 -1
- snowflake/cli/api/console/abc.py +13 -2
- snowflake/cli/api/console/console.py +20 -0
- snowflake/cli/api/constants.py +9 -0
- snowflake/cli/api/entities/utils.py +10 -6
- snowflake/cli/api/feature_flags.py +3 -2
- snowflake/cli/api/identifiers.py +18 -1
- snowflake/cli/api/project/schemas/entities/entities.py +0 -6
- snowflake/cli/api/rendering/sql_templates.py +2 -0
- {snowflake_cli-3.11.0.dist-info → snowflake_cli-3.13.0.dist-info}/METADATA +7 -7
- {snowflake_cli-3.11.0.dist-info → snowflake_cli-3.13.0.dist-info}/RECORD +51 -54
- snowflake/cli/_plugins/auth/keypair/__init__.py +0 -0
- snowflake/cli/_plugins/auth/keypair/commands.py +0 -153
- snowflake/cli/_plugins/auth/keypair/manager.py +0 -331
- snowflake/cli/_plugins/dcm/dcm_project_entity_model.py +0 -59
- snowflake/cli/_plugins/sql/snowsql_commands.py +0 -331
- /snowflake/cli/_plugins/auth/{keypair/plugin_spec.py → plugin_spec.py} +0 -0
- {snowflake_cli-3.11.0.dist-info → snowflake_cli-3.13.0.dist-info}/WHEEL +0 -0
- {snowflake_cli-3.11.0.dist-info → snowflake_cli-3.13.0.dist-info}/entry_points.txt +0 -0
- {snowflake_cli-3.11.0.dist-info → snowflake_cli-3.13.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
import enum
|
|
2
|
-
import re
|
|
3
|
-
import time
|
|
4
|
-
from dataclasses import dataclass
|
|
5
|
-
from datetime import datetime
|
|
6
|
-
from typing import Any, Dict, Generator, Iterable, List, Tuple
|
|
7
|
-
from urllib.parse import urlencode
|
|
8
|
-
|
|
9
|
-
from snowflake.cli._app.printing import print_result
|
|
10
|
-
from snowflake.cli.api.output.types import CollectionResult, QueryResult
|
|
11
|
-
from snowflake.connector import SnowflakeConnection
|
|
12
|
-
|
|
13
|
-
VALID_UUID_RE = re.compile(
|
|
14
|
-
r"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class CommandType(enum.Enum):
|
|
19
|
-
QUERIES = "queries"
|
|
20
|
-
UNKNOWN = "unknown"
|
|
21
|
-
URL = "url"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class SnowSQLCommand:
|
|
25
|
-
def execute(self, connection: SnowflakeConnection):
|
|
26
|
-
"""Executes command and prints the result."""
|
|
27
|
-
raise NotImplementedError
|
|
28
|
-
|
|
29
|
-
@classmethod
|
|
30
|
-
def from_args(cls, args, kwargs) -> "CompileCommandResult":
|
|
31
|
-
"""Validates arguments and creates command ready for execution."""
|
|
32
|
-
raise NotImplementedError
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def _print_result_to_stdout(headers: Iterable[str], rows: Iterable[Iterable[Any]]):
|
|
36
|
-
formatted_rows: Generator[Dict[str, Any], None, None] = (
|
|
37
|
-
{key: value for key, value in zip(headers, row)} for row in rows
|
|
38
|
-
)
|
|
39
|
-
print_result(CollectionResult(formatted_rows))
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
@dataclass
|
|
43
|
-
class CompileCommandResult:
|
|
44
|
-
command: SnowSQLCommand | None = None
|
|
45
|
-
error_message: str | None = None
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@dataclass
|
|
49
|
-
class QueriesCommand(SnowSQLCommand):
|
|
50
|
-
help_mode: bool = False
|
|
51
|
-
from_current_session: bool = False
|
|
52
|
-
amount: int = 25
|
|
53
|
-
user: str | None = None
|
|
54
|
-
warehouse: str | None = None
|
|
55
|
-
start_timestamp_ms: int | None = None
|
|
56
|
-
end_timestamp_ms: int | None = None
|
|
57
|
-
duration: str | None = None
|
|
58
|
-
stmt_type: str | None = None
|
|
59
|
-
status: str | None = None
|
|
60
|
-
|
|
61
|
-
def execute(self, connection: SnowflakeConnection) -> None:
|
|
62
|
-
if self.help_mode:
|
|
63
|
-
self._execute_help()
|
|
64
|
-
else:
|
|
65
|
-
self._execute_queries(connection)
|
|
66
|
-
|
|
67
|
-
def _execute_help(self):
|
|
68
|
-
headers = ["FILTER", "ARGUMENT", "DEFAULT"]
|
|
69
|
-
filters = [
|
|
70
|
-
["amount", "integer", "25"],
|
|
71
|
-
["status", "string", "any"],
|
|
72
|
-
["warehouse", "string", "any"],
|
|
73
|
-
["user", "string", "any"],
|
|
74
|
-
[
|
|
75
|
-
"start_date",
|
|
76
|
-
"datetime in ISO format (for example YYYY-MM-DDTHH:mm:ss.sss)",
|
|
77
|
-
"any",
|
|
78
|
-
],
|
|
79
|
-
[
|
|
80
|
-
"end_date",
|
|
81
|
-
"datetime in ISO format (for example YYYY-MM-DDTHH:mm:ss.sss)",
|
|
82
|
-
"any",
|
|
83
|
-
],
|
|
84
|
-
["start", "timestamp in milliseconds (integer)", "any"],
|
|
85
|
-
["end", "timestamp in milliseconds (integer)", "any"],
|
|
86
|
-
["type", "string", "any"],
|
|
87
|
-
["duration", "time in milliseconds", "any"],
|
|
88
|
-
["session", "No arguments", "any"],
|
|
89
|
-
]
|
|
90
|
-
_print_result_to_stdout(headers, filters)
|
|
91
|
-
|
|
92
|
-
def _execute_queries(self, connection: SnowflakeConnection) -> None:
|
|
93
|
-
url_parameters = {
|
|
94
|
-
"_dc": f"{time.time()}",
|
|
95
|
-
"includeDDL": "false",
|
|
96
|
-
"max": self.amount,
|
|
97
|
-
}
|
|
98
|
-
if self.user:
|
|
99
|
-
url_parameters["user"] = self.user
|
|
100
|
-
if self.warehouse:
|
|
101
|
-
url_parameters["wh"] = self.warehouse
|
|
102
|
-
if self.start_timestamp_ms:
|
|
103
|
-
url_parameters["start"] = self.start_timestamp_ms
|
|
104
|
-
if self.end_timestamp_ms:
|
|
105
|
-
url_parameters["end"] = self.end_timestamp_ms
|
|
106
|
-
if self.duration:
|
|
107
|
-
url_parameters["min_duration"] = self.duration
|
|
108
|
-
if self.from_current_session:
|
|
109
|
-
url_parameters["session_id"] = connection.session_id
|
|
110
|
-
if self.status:
|
|
111
|
-
url_parameters["subset"] = self.status
|
|
112
|
-
if self.stmt_type:
|
|
113
|
-
url_parameters["stmt_type"] = self.stmt_type
|
|
114
|
-
|
|
115
|
-
url = "/monitoring/queries?" + urlencode(url_parameters)
|
|
116
|
-
ret = connection.rest.request(url=url, method="get", client="rest")
|
|
117
|
-
if ret.get("data") and ret["data"].get("queries"):
|
|
118
|
-
_result: Generator[Tuple[str, str, str, str], None, None] = (
|
|
119
|
-
(
|
|
120
|
-
query["id"],
|
|
121
|
-
query["sqlText"],
|
|
122
|
-
query["state"],
|
|
123
|
-
query["totalDuration"],
|
|
124
|
-
)
|
|
125
|
-
for query in ret["data"]["queries"]
|
|
126
|
-
)
|
|
127
|
-
_print_result_to_stdout(
|
|
128
|
-
["QUERY ID", "SQL TEXT", "STATUS", "DURATION_MS"], _result
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
@classmethod
|
|
132
|
-
def from_args(cls, args: List[str], kwargs: Dict[str, Any]) -> CompileCommandResult:
|
|
133
|
-
if "help" in args:
|
|
134
|
-
return CompileCommandResult(command=cls(help_mode=True))
|
|
135
|
-
|
|
136
|
-
# "session" is set by default if no other arguments are provided
|
|
137
|
-
from_current_session = "session" in args or not kwargs
|
|
138
|
-
amount = kwargs.pop("amount", "25")
|
|
139
|
-
if not amount.isdigit():
|
|
140
|
-
return CompileCommandResult(
|
|
141
|
-
error_message=f"Invalid argument passed to 'amount' filter: {amount}"
|
|
142
|
-
)
|
|
143
|
-
user = kwargs.pop("user", None)
|
|
144
|
-
warehouse = kwargs.pop("warehouse", None)
|
|
145
|
-
duration = kwargs.pop("duration", None)
|
|
146
|
-
|
|
147
|
-
start_timestamp_ms = kwargs.pop("start", None)
|
|
148
|
-
if start_timestamp_ms:
|
|
149
|
-
try:
|
|
150
|
-
start_timestamp_ms = int(start_timestamp_ms)
|
|
151
|
-
except ValueError:
|
|
152
|
-
return CompileCommandResult(
|
|
153
|
-
error_message=f"Invalid argument passed to 'start' filter: {start_timestamp_ms}"
|
|
154
|
-
)
|
|
155
|
-
end_timestamp_ms = kwargs.pop("end", None)
|
|
156
|
-
if end_timestamp_ms:
|
|
157
|
-
try:
|
|
158
|
-
end_timestamp_ms = int(end_timestamp_ms)
|
|
159
|
-
except ValueError:
|
|
160
|
-
return CompileCommandResult(
|
|
161
|
-
error_message=f"Invalid argument passed to 'end' filter: {end_timestamp_ms}"
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
start_date = kwargs.pop("start_date", None)
|
|
165
|
-
if start_date:
|
|
166
|
-
if start_timestamp_ms:
|
|
167
|
-
return CompileCommandResult(
|
|
168
|
-
error_message=f"'start_date' filter cannot be used with 'start' filter"
|
|
169
|
-
)
|
|
170
|
-
try:
|
|
171
|
-
seconds = datetime.fromisoformat(start_date).timestamp()
|
|
172
|
-
start_timestamp_ms = int(seconds * 1000) # convert to milliseconds
|
|
173
|
-
except ValueError:
|
|
174
|
-
return CompileCommandResult(
|
|
175
|
-
error_message=f"Invalid date format passed to 'start_date' filter: {start_date}"
|
|
176
|
-
)
|
|
177
|
-
end_date = kwargs.pop("end_date", None)
|
|
178
|
-
if end_date:
|
|
179
|
-
if end_timestamp_ms:
|
|
180
|
-
return CompileCommandResult(
|
|
181
|
-
error_message=f"'end_date' filter cannot be used with 'end' filter"
|
|
182
|
-
)
|
|
183
|
-
try:
|
|
184
|
-
seconds = datetime.fromisoformat(end_date).timestamp()
|
|
185
|
-
end_timestamp_ms = int(seconds * 1000) # convert to milliseconds
|
|
186
|
-
except ValueError:
|
|
187
|
-
return CompileCommandResult(
|
|
188
|
-
error_message=f"Invalid date format passed to 'end_date' filter: {end_date}"
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
stmt_type = kwargs.pop("type", None)
|
|
192
|
-
if stmt_type:
|
|
193
|
-
stmt_type = stmt_type.upper()
|
|
194
|
-
if stmt_type not in [
|
|
195
|
-
"ANY",
|
|
196
|
-
"SELECT",
|
|
197
|
-
"INSERT",
|
|
198
|
-
"UPDATE",
|
|
199
|
-
"DELETE",
|
|
200
|
-
"MERGE",
|
|
201
|
-
"MULTI_TABLE_INSERT",
|
|
202
|
-
"COPY",
|
|
203
|
-
"COMMIT",
|
|
204
|
-
"ROLLBACK",
|
|
205
|
-
"BEGIN_TRANSACTION",
|
|
206
|
-
"SHOW",
|
|
207
|
-
"GRANT",
|
|
208
|
-
"CREATE",
|
|
209
|
-
"ALTER",
|
|
210
|
-
]:
|
|
211
|
-
return CompileCommandResult(
|
|
212
|
-
error_message=f"Invalid argument passed to 'type' filter: {stmt_type}"
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
status = kwargs.pop("status", None)
|
|
216
|
-
if status:
|
|
217
|
-
status = status.upper()
|
|
218
|
-
if status not in [
|
|
219
|
-
"RUNNING",
|
|
220
|
-
"SUCCEEDED",
|
|
221
|
-
"FAILED",
|
|
222
|
-
"BLOCKED",
|
|
223
|
-
"QUEUED",
|
|
224
|
-
"ABORTED",
|
|
225
|
-
]:
|
|
226
|
-
return CompileCommandResult(
|
|
227
|
-
error_message=f"Invalid argument passed to 'status' filter: {status}"
|
|
228
|
-
)
|
|
229
|
-
|
|
230
|
-
for arg in args:
|
|
231
|
-
if arg.lower() not in ["session", "help"]:
|
|
232
|
-
return CompileCommandResult(
|
|
233
|
-
error_message=f"Invalid argument passed to 'queries' command: {arg}"
|
|
234
|
-
)
|
|
235
|
-
if kwargs:
|
|
236
|
-
key, value = kwargs.popitem()
|
|
237
|
-
return CompileCommandResult(
|
|
238
|
-
error_message=f"Invalid argument passed to 'queries' command: {key}={value}"
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
return CompileCommandResult(
|
|
242
|
-
command=cls(
|
|
243
|
-
help_mode=False,
|
|
244
|
-
from_current_session=from_current_session,
|
|
245
|
-
amount=int(amount),
|
|
246
|
-
user=user,
|
|
247
|
-
warehouse=warehouse,
|
|
248
|
-
start_timestamp_ms=start_timestamp_ms,
|
|
249
|
-
end_timestamp_ms=end_timestamp_ms,
|
|
250
|
-
duration=duration,
|
|
251
|
-
stmt_type=stmt_type,
|
|
252
|
-
status=status,
|
|
253
|
-
)
|
|
254
|
-
)
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
def _validate_only_arg_is_query_id(
|
|
258
|
-
command_name: str, args: List[str], kwargs: Dict[str, Any]
|
|
259
|
-
) -> str | None:
|
|
260
|
-
if kwargs:
|
|
261
|
-
key, value = kwargs.popitem()
|
|
262
|
-
return f"Invalid argument passed to '{command_name}' command: {key}={value}"
|
|
263
|
-
if len(args) != 1:
|
|
264
|
-
amount = "Too many" if args else "No"
|
|
265
|
-
return f"{amount} arguments passed to '{command_name}' command. Usage: `!{command_name} <query id>`"
|
|
266
|
-
|
|
267
|
-
qid = args[0]
|
|
268
|
-
if not VALID_UUID_RE.match(qid):
|
|
269
|
-
return f"Invalid query ID passed to '{command_name}' command: {qid}"
|
|
270
|
-
|
|
271
|
-
return None
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
@dataclass
|
|
275
|
-
class ResultCommand(SnowSQLCommand):
|
|
276
|
-
query_id: str
|
|
277
|
-
|
|
278
|
-
def execute(self, connection: SnowflakeConnection):
|
|
279
|
-
cursor = connection.cursor()
|
|
280
|
-
cursor.query_result(self.query_id)
|
|
281
|
-
print_result(QueryResult(cursor=cursor))
|
|
282
|
-
|
|
283
|
-
@classmethod
|
|
284
|
-
def from_args(cls, args, kwargs) -> CompileCommandResult:
|
|
285
|
-
error_msg = _validate_only_arg_is_query_id("result", args, kwargs)
|
|
286
|
-
if error_msg:
|
|
287
|
-
return CompileCommandResult(error_message=error_msg)
|
|
288
|
-
return CompileCommandResult(command=cls(args[0]))
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
@dataclass
|
|
292
|
-
class AbortCommand(SnowSQLCommand):
|
|
293
|
-
query_id: str
|
|
294
|
-
|
|
295
|
-
def execute(self, connection: SnowflakeConnection):
|
|
296
|
-
cursor = connection.cursor()
|
|
297
|
-
cursor.execute(f"SELECT SYSTEM$CANCEL_QUERY('{self.query_id}')")
|
|
298
|
-
print_result(QueryResult(cursor=cursor))
|
|
299
|
-
|
|
300
|
-
@classmethod
|
|
301
|
-
def from_args(cls, args, kwargs) -> CompileCommandResult:
|
|
302
|
-
error_msg = _validate_only_arg_is_query_id("abort", args, kwargs)
|
|
303
|
-
if error_msg:
|
|
304
|
-
return CompileCommandResult(error_message=error_msg)
|
|
305
|
-
return CompileCommandResult(command=cls(args[0]))
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
def compile_snowsql_command(command: str, cmd_args: List[str]):
|
|
309
|
-
"""Parses command into SQL query"""
|
|
310
|
-
args = []
|
|
311
|
-
kwargs = {}
|
|
312
|
-
for cmd_arg in cmd_args:
|
|
313
|
-
if "=" not in cmd_arg:
|
|
314
|
-
args.append(cmd_arg)
|
|
315
|
-
else:
|
|
316
|
-
key, val = cmd_arg.split("=", maxsplit=1)
|
|
317
|
-
if key in kwargs:
|
|
318
|
-
return CompileCommandResult(
|
|
319
|
-
error_message=f"duplicated argument '{key}' for command '{command}'",
|
|
320
|
-
)
|
|
321
|
-
kwargs[key] = val
|
|
322
|
-
|
|
323
|
-
match command.lower():
|
|
324
|
-
case "!queries":
|
|
325
|
-
return QueriesCommand.from_args(args, kwargs)
|
|
326
|
-
case "!result":
|
|
327
|
-
return ResultCommand.from_args(args, kwargs)
|
|
328
|
-
case "!abort":
|
|
329
|
-
return AbortCommand.from_args(args, kwargs)
|
|
330
|
-
case _:
|
|
331
|
-
return CompileCommandResult(error_message=f"Unknown command '{command}'")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|