snowflake-cli 3.9.0__py3-none-any.whl → 3.10.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/printing.py +53 -13
- snowflake/cli/_app/snow_connector.py +1 -0
- snowflake/cli/_app/telemetry.py +2 -0
- snowflake/cli/_app/version_check.py +73 -6
- snowflake/cli/_plugins/cortex/commands.py +8 -3
- snowflake/cli/_plugins/cortex/manager.py +24 -20
- snowflake/cli/_plugins/dbt/commands.py +5 -2
- snowflake/cli/_plugins/git/manager.py +1 -11
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +4 -0
- snowflake/cli/_plugins/nativeapp/commands.py +3 -4
- snowflake/cli/_plugins/nativeapp/entities/application_package.py +1 -1
- snowflake/cli/_plugins/nativeapp/release_channel/commands.py +1 -2
- snowflake/cli/_plugins/nativeapp/version/commands.py +1 -2
- snowflake/cli/_plugins/project/commands.py +61 -10
- snowflake/cli/_plugins/project/manager.py +20 -1
- snowflake/cli/_plugins/snowpark/common.py +23 -11
- snowflake/cli/_plugins/snowpark/snowpark_entity.py +13 -5
- snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +10 -2
- snowflake/cli/_plugins/spcs/image_registry/commands.py +2 -2
- snowflake/cli/_plugins/spcs/image_registry/manager.py +2 -2
- snowflake/cli/_plugins/sql/commands.py +49 -1
- snowflake/cli/_plugins/sql/manager.py +14 -4
- snowflake/cli/_plugins/sql/repl.py +4 -0
- snowflake/cli/_plugins/stage/commands.py +30 -11
- snowflake/cli/_plugins/stage/diff.py +2 -0
- snowflake/cli/_plugins/stage/manager.py +79 -55
- snowflake/cli/_plugins/streamlit/streamlit_entity.py +17 -30
- snowflake/cli/api/artifacts/upload.py +1 -1
- snowflake/cli/api/cli_global_context.py +5 -14
- snowflake/cli/api/commands/decorators.py +7 -0
- snowflake/cli/api/commands/flags.py +12 -0
- snowflake/cli/api/commands/snow_typer.py +23 -2
- snowflake/cli/api/config.py +9 -5
- snowflake/cli/api/connections.py +1 -0
- snowflake/cli/api/entities/common.py +16 -13
- snowflake/cli/api/entities/utils.py +15 -9
- snowflake/cli/api/feature_flags.py +2 -5
- snowflake/cli/api/output/formats.py +6 -0
- snowflake/cli/api/output/types.py +48 -2
- snowflake/cli/api/rendering/sql_templates.py +67 -11
- snowflake/cli/api/stage_path.py +37 -5
- {snowflake_cli-3.9.0.dist-info → snowflake_cli-3.10.0.dist-info}/METADATA +45 -12
- {snowflake_cli-3.9.0.dist-info → snowflake_cli-3.10.0.dist-info}/RECORD +47 -48
- snowflake/cli/_plugins/project/feature_flags.py +0 -22
- {snowflake_cli-3.9.0.dist-info → snowflake_cli-3.10.0.dist-info}/WHEEL +0 -0
- {snowflake_cli-3.9.0.dist-info → snowflake_cli-3.10.0.dist-info}/entry_points.txt +0 -0
- {snowflake_cli-3.9.0.dist-info → snowflake_cli-3.10.0.dist-info}/licenses/LICENSE +0 -0
snowflake/cli/__about__.py
CHANGED
snowflake/cli/_app/printing.py
CHANGED
|
@@ -14,9 +14,11 @@
|
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
|
+
import csv
|
|
17
18
|
import json
|
|
18
19
|
import sys
|
|
19
|
-
from datetime import date, datetime
|
|
20
|
+
from datetime import date, datetime, time
|
|
21
|
+
from decimal import Decimal
|
|
20
22
|
from json import JSONEncoder
|
|
21
23
|
from pathlib import Path
|
|
22
24
|
from textwrap import indent
|
|
@@ -57,10 +59,12 @@ class CustomJSONEncoder(JSONEncoder):
|
|
|
57
59
|
return o.result
|
|
58
60
|
if isinstance(o, (CollectionResult, MultipleResults)):
|
|
59
61
|
return list(o.result)
|
|
60
|
-
if isinstance(o, (date, datetime)):
|
|
62
|
+
if isinstance(o, (date, datetime, time)):
|
|
61
63
|
return o.isoformat()
|
|
62
|
-
if isinstance(o, Path):
|
|
64
|
+
if isinstance(o, (Path, Decimal)):
|
|
63
65
|
return str(o)
|
|
66
|
+
if isinstance(o, bytearray):
|
|
67
|
+
return o.hex()
|
|
64
68
|
return super().default(o)
|
|
65
69
|
|
|
66
70
|
|
|
@@ -86,36 +90,72 @@ def _print_multiple_table_results(obj: CollectionResult):
|
|
|
86
90
|
for column in first_item.keys():
|
|
87
91
|
table.add_column(column, overflow="fold")
|
|
88
92
|
with Live(table, refresh_per_second=4):
|
|
89
|
-
table.add_row(*[
|
|
93
|
+
table.add_row(*[__to_str(i) for i in first_item.values()])
|
|
90
94
|
for item in items:
|
|
91
|
-
table.add_row(*[
|
|
95
|
+
table.add_row(*[__to_str(i) for i in item.values()])
|
|
92
96
|
# Add separator between tables
|
|
93
97
|
rich_print(flush=True)
|
|
94
98
|
|
|
95
99
|
|
|
100
|
+
def __to_str(val):
|
|
101
|
+
if isinstance(val, bytearray):
|
|
102
|
+
return val.hex()
|
|
103
|
+
return str(val)
|
|
104
|
+
|
|
105
|
+
|
|
96
106
|
def is_structured_format(output_format):
|
|
97
|
-
return output_format == OutputFormat.
|
|
107
|
+
return output_format.is_json or output_format == OutputFormat.CSV
|
|
98
108
|
|
|
99
109
|
|
|
100
|
-
def print_structured(
|
|
110
|
+
def print_structured(
|
|
111
|
+
result: CommandResult, output_format: OutputFormat = OutputFormat.JSON
|
|
112
|
+
):
|
|
101
113
|
"""Handles outputs like json, yml and other structured and parsable formats."""
|
|
102
114
|
printed_end_line = False
|
|
103
115
|
if isinstance(result, MultipleResults):
|
|
104
|
-
|
|
116
|
+
if output_format == OutputFormat.CSV:
|
|
117
|
+
for command_result in result.result:
|
|
118
|
+
_print_csv_result(command_result)
|
|
119
|
+
print(flush=True)
|
|
120
|
+
printed_end_line = True
|
|
121
|
+
else:
|
|
122
|
+
_stream_json(result)
|
|
105
123
|
elif isinstance(result, StreamResult):
|
|
106
124
|
# A StreamResult prints each value onto its own line
|
|
107
|
-
# instead of joining all the values into a JSON array
|
|
125
|
+
# instead of joining all the values into a JSON array or CSV entry set
|
|
108
126
|
for r in result.result:
|
|
109
|
-
|
|
127
|
+
if output_format == OutputFormat.CSV:
|
|
128
|
+
_print_csv_result(r.result)
|
|
129
|
+
else:
|
|
130
|
+
json.dump(r, sys.stdout, cls=CustomJSONEncoder)
|
|
110
131
|
print(flush=True)
|
|
111
132
|
printed_end_line = True
|
|
112
133
|
else:
|
|
113
|
-
|
|
134
|
+
if output_format == OutputFormat.CSV:
|
|
135
|
+
_print_csv_result(result)
|
|
136
|
+
printed_end_line = True
|
|
137
|
+
else:
|
|
138
|
+
json.dump(result, sys.stdout, cls=CustomJSONEncoder, indent=4)
|
|
114
139
|
# Adds empty line at the end
|
|
115
140
|
if not printed_end_line:
|
|
116
141
|
print(flush=True)
|
|
117
142
|
|
|
118
143
|
|
|
144
|
+
def _print_csv_result(result: CommandResult):
|
|
145
|
+
data = json.loads(json.dumps(result, cls=CustomJSONEncoder))
|
|
146
|
+
if isinstance(data, dict):
|
|
147
|
+
writer = csv.DictWriter(sys.stdout, [*data], lineterminator="\n")
|
|
148
|
+
writer.writeheader()
|
|
149
|
+
writer.writerow(data)
|
|
150
|
+
elif isinstance(data, list):
|
|
151
|
+
if not data:
|
|
152
|
+
return
|
|
153
|
+
writer = csv.DictWriter(sys.stdout, [*data[0]], lineterminator="\n")
|
|
154
|
+
writer.writeheader()
|
|
155
|
+
for entry in data:
|
|
156
|
+
writer.writerow(entry)
|
|
157
|
+
|
|
158
|
+
|
|
119
159
|
def _stream_json(result):
|
|
120
160
|
"""Simple helper for streaming multiple results as a JSON."""
|
|
121
161
|
indent_size = 2
|
|
@@ -160,7 +200,7 @@ def _print_single_table(obj):
|
|
|
160
200
|
table.add_column("value", overflow="fold")
|
|
161
201
|
for key, value in obj.result.items():
|
|
162
202
|
table.add_row(
|
|
163
|
-
sanitize_for_terminal(str(key)), sanitize_for_terminal(
|
|
203
|
+
sanitize_for_terminal(str(key)), sanitize_for_terminal(__to_str(value))
|
|
164
204
|
)
|
|
165
205
|
rich_print(table, flush=True)
|
|
166
206
|
|
|
@@ -168,7 +208,7 @@ def _print_single_table(obj):
|
|
|
168
208
|
def print_result(cmd_result: CommandResult, output_format: OutputFormat | None = None):
|
|
169
209
|
output_format = output_format or _get_format_type()
|
|
170
210
|
if is_structured_format(output_format):
|
|
171
|
-
print_structured(cmd_result)
|
|
211
|
+
print_structured(cmd_result, output_format)
|
|
172
212
|
elif isinstance(cmd_result, (MultipleResults, StreamResult)):
|
|
173
213
|
for res in cmd_result.result:
|
|
174
214
|
print_result(res)
|
snowflake/cli/_app/telemetry.py
CHANGED
|
@@ -178,6 +178,8 @@ def _get_definition_version() -> str | None:
|
|
|
178
178
|
|
|
179
179
|
|
|
180
180
|
def _get_ci_environment_type() -> str:
|
|
181
|
+
if "SF_GITHUB_ACTION" in os.environ:
|
|
182
|
+
return "SF_GITHUB_ACTION"
|
|
181
183
|
if "GITHUB_ACTIONS" in os.environ:
|
|
182
184
|
return "GITHUB_ACTIONS"
|
|
183
185
|
if "GITLAB_CI" in os.environ:
|
|
@@ -6,18 +6,54 @@ import requests
|
|
|
6
6
|
from packaging.version import Version
|
|
7
7
|
from snowflake.cli.__about__ import VERSION
|
|
8
8
|
from snowflake.cli.api.cli_global_context import get_cli_context
|
|
9
|
+
from snowflake.cli.api.config import (
|
|
10
|
+
CLI_SECTION,
|
|
11
|
+
IGNORE_NEW_VERSION_WARNING_KEY,
|
|
12
|
+
get_config_bool_value,
|
|
13
|
+
)
|
|
9
14
|
from snowflake.cli.api.secure_path import SecurePath
|
|
10
15
|
from snowflake.connector.config_manager import CONFIG_MANAGER
|
|
11
16
|
|
|
12
17
|
REPOSITORY_URL_PIP = "https://pypi.org/pypi/snowflake-cli/json"
|
|
13
18
|
REPOSITORY_URL_BREW = "https://formulae.brew.sh/api/formula/snowflake-cli.json"
|
|
14
19
|
|
|
20
|
+
# How often to refresh the version cache (seconds)
|
|
21
|
+
VERSION_CACHE_REFRESH_INTERVAL = 60 * 60 # 1 hour
|
|
22
|
+
# How often to show the new version message (seconds)
|
|
23
|
+
NEW_VERSION_MESSAGE_INTERVAL = 60 * 60 * 24 * 7 # 1 week
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def should_ignore_new_version_warning() -> bool:
|
|
27
|
+
return get_config_bool_value(
|
|
28
|
+
CLI_SECTION, key=IGNORE_NEW_VERSION_WARNING_KEY, default=False
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def was_warning_shown_recently(last_time_shown: float | int | None) -> bool:
|
|
33
|
+
"""
|
|
34
|
+
Returns True if the new version warning was shown recently (within the interval),
|
|
35
|
+
meaning we should NOT show the warning again yet.
|
|
36
|
+
"""
|
|
37
|
+
if not last_time_shown:
|
|
38
|
+
return False
|
|
39
|
+
now = time.time()
|
|
40
|
+
return last_time_shown >= now - NEW_VERSION_MESSAGE_INTERVAL
|
|
41
|
+
|
|
15
42
|
|
|
16
43
|
def get_new_version_msg() -> str | None:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
44
|
+
if should_ignore_new_version_warning():
|
|
45
|
+
return None
|
|
46
|
+
cache = _VersionCache()
|
|
47
|
+
last_version = cache.get_last_version()
|
|
48
|
+
last_time_shown = cache.get_last_time_shown()
|
|
49
|
+
current_version = Version(VERSION)
|
|
50
|
+
if (
|
|
51
|
+
last_version
|
|
52
|
+
and last_version > current_version
|
|
53
|
+
and not was_warning_shown_recently(last_time_shown)
|
|
54
|
+
):
|
|
55
|
+
cache.update_last_time_shown()
|
|
56
|
+
return f"\nNew version of Snowflake CLI available. Newest: {last_version}, current: {VERSION}\n"
|
|
21
57
|
return None
|
|
22
58
|
|
|
23
59
|
|
|
@@ -32,6 +68,7 @@ def show_new_version_banner_callback(msg):
|
|
|
32
68
|
class _VersionCache:
|
|
33
69
|
_last_time = "last_time_check"
|
|
34
70
|
_version = "version"
|
|
71
|
+
_last_time_shown = "last_time_shown"
|
|
35
72
|
_version_cache_file = SecurePath(
|
|
36
73
|
CONFIG_MANAGER.file_path.parent / ".cli_version.cache"
|
|
37
74
|
)
|
|
@@ -44,6 +81,28 @@ class _VersionCache:
|
|
|
44
81
|
_VersionCache._last_time: time.time(),
|
|
45
82
|
_VersionCache._version: str(version),
|
|
46
83
|
}
|
|
84
|
+
if self._cache_file.exists():
|
|
85
|
+
try:
|
|
86
|
+
old_data = json.loads(self._cache_file.read_text(file_size_limit_mb=1))
|
|
87
|
+
if _VersionCache._last_time_shown in old_data:
|
|
88
|
+
data[_VersionCache._last_time_shown] = old_data[
|
|
89
|
+
_VersionCache._last_time_shown
|
|
90
|
+
]
|
|
91
|
+
except Exception:
|
|
92
|
+
pass
|
|
93
|
+
self._cache_file.parent.mkdir(parents=True, exist_ok=True)
|
|
94
|
+
self._cache_file.write_text(json.dumps(data))
|
|
95
|
+
|
|
96
|
+
def update_last_time_shown(self):
|
|
97
|
+
if self._cache_file.exists():
|
|
98
|
+
try:
|
|
99
|
+
data = json.loads(self._cache_file.read_text(file_size_limit_mb=1))
|
|
100
|
+
except Exception:
|
|
101
|
+
data = {}
|
|
102
|
+
else:
|
|
103
|
+
data = {}
|
|
104
|
+
data[_VersionCache._last_time_shown] = time.time()
|
|
105
|
+
self._cache_file.parent.mkdir(parents=True, exist_ok=True)
|
|
47
106
|
self._cache_file.write_text(json.dumps(data))
|
|
48
107
|
|
|
49
108
|
@staticmethod
|
|
@@ -73,9 +132,8 @@ class _VersionCache:
|
|
|
73
132
|
if self._cache_file.exists():
|
|
74
133
|
data = json.loads(self._cache_file.read_text(file_size_limit_mb=1))
|
|
75
134
|
now = time.time()
|
|
76
|
-
if data[_VersionCache._last_time] > now -
|
|
135
|
+
if data[_VersionCache._last_time] > now - VERSION_CACHE_REFRESH_INTERVAL:
|
|
77
136
|
return Version(data[_VersionCache._version])
|
|
78
|
-
|
|
79
137
|
return self._update_latest_version()
|
|
80
138
|
|
|
81
139
|
def get_last_version(self) -> Version | None:
|
|
@@ -83,3 +141,12 @@ class _VersionCache:
|
|
|
83
141
|
return self._read_latest_version()
|
|
84
142
|
except: # anything, this it not crucial feature
|
|
85
143
|
return None
|
|
144
|
+
|
|
145
|
+
def get_last_time_shown(self) -> float | int | None:
|
|
146
|
+
if self._cache_file.exists():
|
|
147
|
+
try:
|
|
148
|
+
data = json.loads(self._cache_file.read_text(file_size_limit_mb=1))
|
|
149
|
+
return data.get(_VersionCache._last_time_shown, 0)
|
|
150
|
+
except Exception:
|
|
151
|
+
return None
|
|
152
|
+
return None
|
|
@@ -41,6 +41,7 @@ from snowflake.cli.api.commands.overrideable_parameter import (
|
|
|
41
41
|
)
|
|
42
42
|
from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
|
|
43
43
|
from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB, PYTHON_3_12
|
|
44
|
+
from snowflake.cli.api.exceptions import CliError
|
|
44
45
|
from snowflake.cli.api.output.types import (
|
|
45
46
|
CollectionResult,
|
|
46
47
|
CommandResult,
|
|
@@ -94,6 +95,7 @@ def search(
|
|
|
94
95
|
"""
|
|
95
96
|
Performs query search using Cortex Search Services.
|
|
96
97
|
"""
|
|
98
|
+
from snowflake.core import Root
|
|
97
99
|
|
|
98
100
|
if not SEARCH_COMMAND_ENABLED:
|
|
99
101
|
raise click.ClickException(
|
|
@@ -104,7 +106,12 @@ def search(
|
|
|
104
106
|
columns = []
|
|
105
107
|
|
|
106
108
|
conn = get_cli_context().connection
|
|
107
|
-
|
|
109
|
+
if conn:
|
|
110
|
+
root = Root(conn)
|
|
111
|
+
else:
|
|
112
|
+
raise CliError(
|
|
113
|
+
"Cortex Search requires a connection to be established. Please connect to a Snowflake account first."
|
|
114
|
+
)
|
|
108
115
|
|
|
109
116
|
search_service = (
|
|
110
117
|
root.databases[conn.database]
|
|
@@ -173,11 +180,9 @@ def complete(
|
|
|
173
180
|
is_file_input=is_file_input,
|
|
174
181
|
)
|
|
175
182
|
elif backend == Backend.REST:
|
|
176
|
-
root = get_cli_context().snow_api_root
|
|
177
183
|
result_text = manager.rest_complete(
|
|
178
184
|
text=Text(prompt),
|
|
179
185
|
model=Model(model),
|
|
180
|
-
root=root,
|
|
181
186
|
)
|
|
182
187
|
else:
|
|
183
188
|
raise UsageError("--backend option should be either rest or sql.")
|
|
@@ -26,18 +26,13 @@ from snowflake.cli._plugins.cortex.types import (
|
|
|
26
26
|
SourceDocument,
|
|
27
27
|
Text,
|
|
28
28
|
)
|
|
29
|
+
from snowflake.cli.api.cli_global_context import get_cli_context
|
|
29
30
|
from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB
|
|
30
|
-
from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
|
|
31
|
+
from snowflake.cli.api.exceptions import CliError, SnowflakeSQLExecutionError
|
|
31
32
|
from snowflake.cli.api.secure_path import SecurePath
|
|
32
33
|
from snowflake.cli.api.sql_execution import SqlExecutionMixin
|
|
33
34
|
from snowflake.connector import ProgrammingError
|
|
34
35
|
from snowflake.connector.cursor import DictCursor
|
|
35
|
-
from snowflake.core._root import Root
|
|
36
|
-
from snowflake.core.cortex.inference_service import CortexInferenceService
|
|
37
|
-
from snowflake.core.cortex.inference_service._generated.models import CompleteRequest
|
|
38
|
-
from snowflake.core.cortex.inference_service._generated.models.complete_request_messages_inner import (
|
|
39
|
-
CompleteRequestMessagesInner,
|
|
40
|
-
)
|
|
41
36
|
|
|
42
37
|
log = logging.getLogger(__name__)
|
|
43
38
|
|
|
@@ -89,24 +84,33 @@ class CortexManager(SqlExecutionMixin):
|
|
|
89
84
|
lambda: json_result["choices"][0]["messages"]
|
|
90
85
|
)
|
|
91
86
|
|
|
92
|
-
def make_rest_complete_request(
|
|
93
|
-
self,
|
|
94
|
-
model: Model,
|
|
95
|
-
prompt: Text,
|
|
96
|
-
) -> CompleteRequest:
|
|
97
|
-
return CompleteRequest(
|
|
98
|
-
model=str(model),
|
|
99
|
-
messages=[CompleteRequestMessagesInner(content=str(prompt))],
|
|
100
|
-
stream=True,
|
|
101
|
-
)
|
|
102
|
-
|
|
103
87
|
def rest_complete(
|
|
104
88
|
self,
|
|
105
89
|
text: Text,
|
|
106
90
|
model: Model,
|
|
107
|
-
root: "Root",
|
|
108
91
|
) -> str:
|
|
109
|
-
|
|
92
|
+
from snowflake.core import Root
|
|
93
|
+
from snowflake.core.cortex.inference_service import CortexInferenceService
|
|
94
|
+
from snowflake.core.cortex.inference_service._generated.models import (
|
|
95
|
+
CompleteRequest,
|
|
96
|
+
)
|
|
97
|
+
from snowflake.core.cortex.inference_service._generated.models.complete_request_messages_inner import (
|
|
98
|
+
CompleteRequestMessagesInner,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
cli_context = get_cli_context()
|
|
102
|
+
if cli_context.connection:
|
|
103
|
+
root = Root(cli_context.connection)
|
|
104
|
+
else:
|
|
105
|
+
raise CliError(
|
|
106
|
+
"Cortex Search requires a connection to be established. Please connect to a Snowflake account first."
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
complete_request = CompleteRequest(
|
|
110
|
+
model=str(model),
|
|
111
|
+
messages=[CompleteRequestMessagesInner(content=str(text))],
|
|
112
|
+
stream=True,
|
|
113
|
+
)
|
|
110
114
|
cortex_inference_service = CortexInferenceService(root=root)
|
|
111
115
|
try:
|
|
112
116
|
raw_resp = cortex_inference_service.complete(
|
|
@@ -45,8 +45,9 @@ from snowflake.cli.api.secure_path import SecurePath
|
|
|
45
45
|
|
|
46
46
|
app = SnowTyperFactory(
|
|
47
47
|
name="dbt",
|
|
48
|
-
help="Manages dbt on Snowflake projects",
|
|
48
|
+
help="Manages dbt on Snowflake projects.",
|
|
49
49
|
is_hidden=FeatureFlag.ENABLE_DBT.is_disabled,
|
|
50
|
+
preview=True,
|
|
50
51
|
)
|
|
51
52
|
log = logging.getLogger(__name__)
|
|
52
53
|
|
|
@@ -64,7 +65,7 @@ add_object_command_aliases(
|
|
|
64
65
|
object_type=ObjectType.DBT_PROJECT,
|
|
65
66
|
name_argument=DBTNameArgument,
|
|
66
67
|
like_option=like_option(
|
|
67
|
-
help_example='`list --like "my%"` lists all dbt projects that begin with
|
|
68
|
+
help_example='`list --like "my%"` lists all dbt projects that begin with "my"'
|
|
68
69
|
),
|
|
69
70
|
scope_option=scope_option(help_example="`list --in database my_db`"),
|
|
70
71
|
ommit_commands=["drop", "create", "describe"],
|
|
@@ -115,6 +116,7 @@ dbt_execute_app = SnowTyperFactory(
|
|
|
115
116
|
help="Execute a dbt command on Snowflake. Subcommand name and all "
|
|
116
117
|
"parameters following it will be passed over to dbt.",
|
|
117
118
|
subcommand_metavar="DBT_COMMAND",
|
|
119
|
+
preview=True,
|
|
118
120
|
)
|
|
119
121
|
app.add_typer(dbt_execute_app)
|
|
120
122
|
|
|
@@ -141,6 +143,7 @@ for cmd in DBT_COMMANDS:
|
|
|
141
143
|
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
|
142
144
|
help=f"Execute {cmd} command on Snowflake. Command name and all parameters following it will be passed over to dbt.",
|
|
143
145
|
add_help_option=False,
|
|
146
|
+
preview=True,
|
|
144
147
|
)
|
|
145
148
|
def _dbt_execute(
|
|
146
149
|
ctx: typer.Context,
|
|
@@ -14,9 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
|
-
from pathlib import
|
|
17
|
+
from pathlib import PurePosixPath
|
|
18
18
|
from textwrap import dedent
|
|
19
|
-
from typing import List
|
|
20
19
|
|
|
21
20
|
from click import UsageError
|
|
22
21
|
from snowflake.cli._plugins.stage.manager import (
|
|
@@ -64,19 +63,10 @@ class GitStagePathParts(StagePathParts):
|
|
|
64
63
|
def full_path(self) -> str:
|
|
65
64
|
return f"{self.stage.rstrip('/')}/{self.directory}"
|
|
66
65
|
|
|
67
|
-
def replace_stage_prefix(self, file_path: str) -> str:
|
|
68
|
-
stage = Path(self.stage).parts[0]
|
|
69
|
-
file_path_without_prefix = Path(file_path).parts[OMIT_FIRST]
|
|
70
|
-
return f"{stage}/{'/'.join(file_path_without_prefix)}"
|
|
71
|
-
|
|
72
66
|
def add_stage_prefix(self, file_path: str) -> str:
|
|
73
67
|
stage = self.stage.rstrip("/")
|
|
74
68
|
return f"{stage}/{file_path.lstrip('/')}"
|
|
75
69
|
|
|
76
|
-
def get_directory_from_file_path(self, file_path: str) -> List[str]:
|
|
77
|
-
stage_path_length = len(Path(self.directory).parts)
|
|
78
|
-
return list(Path(file_path).parts[3 + stage_path_length : -1])
|
|
79
|
-
|
|
80
70
|
|
|
81
71
|
class GitManager(StageManager):
|
|
82
72
|
@staticmethod
|
|
@@ -49,6 +49,7 @@ from snowflake.cli._plugins.nativeapp.codegen.snowpark.models import (
|
|
|
49
49
|
from snowflake.cli._plugins.stage.diff import to_stage_path
|
|
50
50
|
from snowflake.cli.api.artifacts.bundle_map import BundleMap
|
|
51
51
|
from snowflake.cli.api.cli_global_context import get_cli_context, span
|
|
52
|
+
from snowflake.cli.api.console import cli_console
|
|
52
53
|
from snowflake.cli.api.console import cli_console as cc
|
|
53
54
|
from snowflake.cli.api.metrics import CLICounterField
|
|
54
55
|
from snowflake.cli.api.project.schemas.entities.common import (
|
|
@@ -181,6 +182,9 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
|
|
|
181
182
|
setup script with generated SQL that registers these functions.
|
|
182
183
|
"""
|
|
183
184
|
|
|
185
|
+
cli_console.warning(
|
|
186
|
+
"Snowpark processor is not supported and will be removed soon."
|
|
187
|
+
)
|
|
184
188
|
get_cli_context().metrics.set_counter(CLICounterField.SNOWPARK_PROCESSOR, 1)
|
|
185
189
|
|
|
186
190
|
bundle_map = BundleMap(
|
|
@@ -55,7 +55,6 @@ from snowflake.cli.api.exceptions import (
|
|
|
55
55
|
IncompatibleParametersError,
|
|
56
56
|
UnmetParametersError,
|
|
57
57
|
)
|
|
58
|
-
from snowflake.cli.api.output.formats import OutputFormat
|
|
59
58
|
from snowflake.cli.api.output.types import (
|
|
60
59
|
CommandResult,
|
|
61
60
|
MessageResult,
|
|
@@ -117,9 +116,9 @@ def app_diff(
|
|
|
117
116
|
diff = ws.perform_action(
|
|
118
117
|
package_id,
|
|
119
118
|
EntityActions.DIFF,
|
|
120
|
-
print_to_console=cli_context.output_format
|
|
119
|
+
print_to_console=not cli_context.output_format.is_json,
|
|
121
120
|
)
|
|
122
|
-
if cli_context.output_format
|
|
121
|
+
if cli_context.output_format.is_json:
|
|
123
122
|
return ObjectResult(diff.to_dict())
|
|
124
123
|
|
|
125
124
|
return None
|
|
@@ -373,7 +372,7 @@ def app_validate(
|
|
|
373
372
|
)
|
|
374
373
|
package_id = options["package_entity_id"]
|
|
375
374
|
package = ws.get_entity(package_id)
|
|
376
|
-
if cli_context.output_format
|
|
375
|
+
if cli_context.output_format.is_json:
|
|
377
376
|
return ObjectResult(
|
|
378
377
|
package.get_validation_result(
|
|
379
378
|
action_ctx=ws.action_ctx,
|
|
@@ -1330,7 +1330,7 @@ class ApplicationPackageEntity(EntityBase[ApplicationPackageEntityModel]):
|
|
|
1330
1330
|
role=self.role,
|
|
1331
1331
|
prune=prune,
|
|
1332
1332
|
recursive=recursive,
|
|
1333
|
-
|
|
1333
|
+
stage_path_parts=stage_path,
|
|
1334
1334
|
local_paths_to_sync=paths,
|
|
1335
1335
|
print_diff=print_diff,
|
|
1336
1336
|
)
|
|
@@ -26,7 +26,6 @@ from snowflake.cli.api.cli_global_context import get_cli_context
|
|
|
26
26
|
from snowflake.cli.api.commands.decorators import with_project_definition
|
|
27
27
|
from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
|
|
28
28
|
from snowflake.cli.api.entities.utils import EntityActions
|
|
29
|
-
from snowflake.cli.api.output.formats import OutputFormat
|
|
30
29
|
from snowflake.cli.api.output.types import (
|
|
31
30
|
CollectionResult,
|
|
32
31
|
CommandResult,
|
|
@@ -68,7 +67,7 @@ def release_channel_list(
|
|
|
68
67
|
release_channel=channel,
|
|
69
68
|
)
|
|
70
69
|
|
|
71
|
-
if cli_context.output_format
|
|
70
|
+
if cli_context.output_format.is_json:
|
|
72
71
|
return CollectionResult(channels)
|
|
73
72
|
|
|
74
73
|
|
|
@@ -30,7 +30,6 @@ from snowflake.cli.api.commands.decorators import (
|
|
|
30
30
|
)
|
|
31
31
|
from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
|
|
32
32
|
from snowflake.cli.api.entities.utils import EntityActions
|
|
33
|
-
from snowflake.cli.api.output.formats import OutputFormat
|
|
34
33
|
from snowflake.cli.api.output.types import (
|
|
35
34
|
CollectionResult,
|
|
36
35
|
CommandResult,
|
|
@@ -105,7 +104,7 @@ def create(
|
|
|
105
104
|
)
|
|
106
105
|
|
|
107
106
|
message = "Version create is now complete."
|
|
108
|
-
if cli_context.output_format
|
|
107
|
+
if cli_context.output_format.is_json:
|
|
109
108
|
return ObjectResult(
|
|
110
109
|
{
|
|
111
110
|
"message": message,
|