snowflake-cli 3.0.2__py3-none-any.whl → 3.1.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 +3 -0
- snowflake/cli/_app/dev/docs/templates/overview.rst.jinja2 +1 -1
- snowflake/cli/_app/dev/docs/templates/usage.rst.jinja2 +2 -2
- snowflake/cli/_app/telemetry.py +69 -4
- snowflake/cli/_plugins/connection/commands.py +40 -2
- snowflake/cli/_plugins/git/commands.py +6 -3
- snowflake/cli/_plugins/git/manager.py +5 -0
- snowflake/cli/_plugins/nativeapp/artifacts.py +13 -3
- snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/compiler.py +7 -0
- snowflake/cli/_plugins/nativeapp/codegen/sandbox.py +10 -10
- snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +2 -2
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/extension_function_utils.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +8 -8
- snowflake/cli/_plugins/nativeapp/commands.py +135 -186
- snowflake/cli/_plugins/nativeapp/entities/application.py +176 -24
- snowflake/cli/_plugins/nativeapp/entities/application_package.py +112 -136
- snowflake/cli/_plugins/nativeapp/exceptions.py +12 -0
- snowflake/cli/_plugins/nativeapp/manager.py +3 -26
- snowflake/cli/_plugins/nativeapp/v2_conversions/{v2_to_v1_decorator.py → compat.py} +131 -72
- snowflake/cli/_plugins/nativeapp/version/commands.py +30 -29
- snowflake/cli/_plugins/nativeapp/version/version_processor.py +1 -43
- snowflake/cli/_plugins/snowpark/common.py +60 -18
- snowflake/cli/_plugins/snowpark/package/anaconda_packages.py +2 -2
- snowflake/cli/_plugins/spcs/image_repository/commands.py +4 -37
- snowflake/cli/_plugins/spcs/image_repository/manager.py +4 -1
- snowflake/cli/_plugins/spcs/services/commands.py +36 -4
- snowflake/cli/_plugins/spcs/services/manager.py +36 -4
- snowflake/cli/_plugins/stage/commands.py +8 -3
- snowflake/cli/_plugins/stage/diff.py +16 -16
- snowflake/cli/_plugins/stage/manager.py +164 -73
- snowflake/cli/_plugins/stage/md5.py +1 -1
- snowflake/cli/_plugins/workspace/commands.py +21 -1
- snowflake/cli/_plugins/workspace/context.py +38 -0
- snowflake/cli/_plugins/workspace/manager.py +23 -13
- snowflake/cli/api/cli_global_context.py +3 -3
- snowflake/cli/api/commands/flags.py +23 -7
- snowflake/cli/api/config.py +7 -4
- snowflake/cli/api/connections.py +12 -1
- snowflake/cli/api/entities/common.py +4 -2
- snowflake/cli/api/entities/utils.py +17 -37
- snowflake/cli/api/exceptions.py +32 -0
- snowflake/cli/api/identifiers.py +8 -0
- snowflake/cli/api/project/definition_conversion.py +139 -40
- snowflake/cli/api/project/schemas/entities/common.py +11 -0
- snowflake/cli/api/project/schemas/project_definition.py +30 -25
- snowflake/cli/api/sql_execution.py +5 -7
- snowflake/cli/api/stage_path.py +241 -0
- snowflake/cli/api/utils/definition_rendering.py +3 -5
- {snowflake_cli-3.0.2.dist-info → snowflake_cli-3.1.0.dist-info}/METADATA +11 -11
- {snowflake_cli-3.0.2.dist-info → snowflake_cli-3.1.0.dist-info}/RECORD +55 -55
- snowflake/cli/_plugins/nativeapp/teardown_processor.py +0 -70
- snowflake/cli/_plugins/workspace/action_context.py +0 -18
- {snowflake_cli-3.0.2.dist-info → snowflake_cli-3.1.0.dist-info}/WHEEL +0 -0
- {snowflake_cli-3.0.2.dist-info → snowflake_cli-3.1.0.dist-info}/entry_points.txt +0 -0
- {snowflake_cli-3.0.2.dist-info → snowflake_cli-3.1.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -19,6 +19,7 @@ from typing import Any, Dict, List, Optional, Union
|
|
|
19
19
|
|
|
20
20
|
from packaging.version import Version
|
|
21
21
|
from pydantic import Field, ValidationError, field_validator, model_validator
|
|
22
|
+
from pydantic_core.core_schema import ValidationInfo
|
|
22
23
|
from snowflake.cli._plugins.nativeapp.entities.application import ApplicationEntityModel
|
|
23
24
|
from snowflake.cli.api.project.errors import SchemaValidationError
|
|
24
25
|
from snowflake.cli.api.project.schemas.entities.common import (
|
|
@@ -115,7 +116,17 @@ class DefinitionV11(DefinitionV10):
|
|
|
115
116
|
|
|
116
117
|
|
|
117
118
|
class DefinitionV20(_ProjectDefinitionBase):
|
|
118
|
-
entities: Dict[str, AnnotatedEntity] = Field(
|
|
119
|
+
entities: Dict[str, AnnotatedEntity] = Field(
|
|
120
|
+
title="Entity definitions.", default={}
|
|
121
|
+
)
|
|
122
|
+
env: Optional[Dict[str, Union[str, int, bool]]] = Field(
|
|
123
|
+
title="Default environment specification for this project.",
|
|
124
|
+
default=None,
|
|
125
|
+
)
|
|
126
|
+
mixins: Optional[Dict[str, Dict]] = Field(
|
|
127
|
+
title="Mixins to apply to entities",
|
|
128
|
+
default=None,
|
|
129
|
+
)
|
|
119
130
|
|
|
120
131
|
@model_validator(mode="after")
|
|
121
132
|
def validate_entities_identifiers(self):
|
|
@@ -163,38 +174,32 @@ class DefinitionV20(_ProjectDefinitionBase):
|
|
|
163
174
|
f"Target type mismatch. Expected {target_type.__name__}, got {actual_target_type.__name__}"
|
|
164
175
|
)
|
|
165
176
|
|
|
166
|
-
env: Optional[Dict[str, Union[str, int, bool]]] = Field(
|
|
167
|
-
title="Default environment specification for this project.",
|
|
168
|
-
default=None,
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
mixins: Optional[Dict[str, Dict]] = Field(
|
|
172
|
-
title="Mixins to apply to entities",
|
|
173
|
-
default=None,
|
|
174
|
-
)
|
|
175
|
-
|
|
176
177
|
@model_validator(mode="before")
|
|
177
178
|
@classmethod
|
|
178
|
-
def apply_mixins(cls, data: Dict) -> Dict:
|
|
179
|
+
def apply_mixins(cls, data: Dict, info: ValidationInfo) -> Dict:
|
|
179
180
|
"""
|
|
180
181
|
Applies mixins to those entities, whose meta field contains the mixin name.
|
|
181
182
|
"""
|
|
182
183
|
if "mixins" not in data or "entities" not in data:
|
|
183
184
|
return data
|
|
184
185
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
duplicated_run = (
|
|
187
|
+
info.context.get("is_duplicated_run", False) if info.context else False
|
|
188
|
+
)
|
|
189
|
+
if not duplicated_run:
|
|
190
|
+
entities = data["entities"]
|
|
191
|
+
for entity_name, entity in entities.items():
|
|
192
|
+
entity_mixins = entity_mixins_to_list(
|
|
193
|
+
entity.get("meta", {}).get("use_mixins")
|
|
194
|
+
)
|
|
190
195
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
merged_values = cls._merge_mixins_with_entity(
|
|
197
|
+
entity_id=entity_name,
|
|
198
|
+
entity=entity,
|
|
199
|
+
entity_mixins_names=entity_mixins,
|
|
200
|
+
mixin_defs=data["mixins"],
|
|
201
|
+
)
|
|
202
|
+
entities[entity_name] = merged_values
|
|
198
203
|
return data
|
|
199
204
|
|
|
200
205
|
@classmethod
|
|
@@ -325,6 +330,6 @@ def get_allowed_fields_for_entity(entity: Dict[str, Any]) -> List[str]:
|
|
|
325
330
|
def _unique_extend(list_a: List, list_b: List) -> List:
|
|
326
331
|
new_list = list(list_a)
|
|
327
332
|
for item in list_b:
|
|
328
|
-
if item
|
|
333
|
+
if all(item != x for x in list_a):
|
|
329
334
|
new_list.append(item)
|
|
330
335
|
return new_list
|
|
@@ -25,8 +25,10 @@ from snowflake.cli.api.cli_global_context import get_cli_context
|
|
|
25
25
|
from snowflake.cli.api.console import cli_console
|
|
26
26
|
from snowflake.cli.api.constants import ObjectType
|
|
27
27
|
from snowflake.cli.api.exceptions import (
|
|
28
|
+
CouldNotUseObjectError,
|
|
28
29
|
DatabaseNotProvidedError,
|
|
29
30
|
SchemaNotProvidedError,
|
|
31
|
+
ShowSpecificObjectMultipleRowsError,
|
|
30
32
|
SnowflakeSQLExecutionError,
|
|
31
33
|
)
|
|
32
34
|
from snowflake.cli.api.identifiers import FQN
|
|
@@ -91,11 +93,9 @@ class SqlExecutor:
|
|
|
91
93
|
def use(self, object_type: ObjectType, name: str):
|
|
92
94
|
try:
|
|
93
95
|
self._execute_query(f"use {object_type.value.sf_name} {name}")
|
|
94
|
-
except ProgrammingError:
|
|
96
|
+
except ProgrammingError as err:
|
|
95
97
|
# Rewrite the error to make the message more useful.
|
|
96
|
-
raise
|
|
97
|
-
f"Could not use {object_type} {name}. Object does not exist, or operation cannot be performed."
|
|
98
|
-
)
|
|
98
|
+
raise CouldNotUseObjectError(object_type=object_type, name=name) from err
|
|
99
99
|
|
|
100
100
|
def current_role(self) -> str:
|
|
101
101
|
return self._execute_query(f"select current_role()").fetchone()[0]
|
|
@@ -247,9 +247,7 @@ class SqlExecutor:
|
|
|
247
247
|
if show_obj_cursor.rowcount is None:
|
|
248
248
|
raise SnowflakeSQLExecutionError(show_obj_query)
|
|
249
249
|
elif show_obj_cursor.rowcount > 1:
|
|
250
|
-
raise
|
|
251
|
-
f"Received multiple rows from result of SQL statement: {show_obj_query}. Usage of 'show_specific_object' may not be properly scoped."
|
|
252
|
-
)
|
|
250
|
+
raise ShowSpecificObjectMultipleRowsError(show_obj_query=show_obj_query)
|
|
253
251
|
|
|
254
252
|
show_obj_row = find_first_row(
|
|
255
253
|
show_obj_cursor,
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from pathlib import Path, PurePosixPath
|
|
5
|
+
|
|
6
|
+
from snowflake.cli.api.identifiers import FQN
|
|
7
|
+
from snowflake.cli.api.project.util import (
|
|
8
|
+
to_string_literal,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
USER_STAGE_PREFIX = "~"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class StagePath:
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
stage_name: str,
|
|
18
|
+
path: str | PurePosixPath | None = None,
|
|
19
|
+
git_ref: str | None = None,
|
|
20
|
+
trailing_slash: bool = False,
|
|
21
|
+
):
|
|
22
|
+
self._stage_name = self.strip_stage_prefixes(stage_name)
|
|
23
|
+
self._path = PurePosixPath(path) if path else PurePosixPath(".")
|
|
24
|
+
|
|
25
|
+
self._trailing_slash = trailing_slash
|
|
26
|
+
# Check if user stage
|
|
27
|
+
self._is_user_stage = self._stage_name.startswith(USER_STAGE_PREFIX)
|
|
28
|
+
|
|
29
|
+
# Setup git information
|
|
30
|
+
self._git_ref = None
|
|
31
|
+
self._is_git_repo = False
|
|
32
|
+
if git_ref:
|
|
33
|
+
self._git_ref = git_ref
|
|
34
|
+
self._is_git_repo = True
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def get_user_stage(cls) -> StagePath:
|
|
38
|
+
return cls.from_stage_str("~")
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def stage(self) -> str:
|
|
42
|
+
return self._stage_name
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def path(self) -> PurePosixPath:
|
|
46
|
+
return self._path
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def stage_with_at(self) -> str:
|
|
50
|
+
return self.add_at_prefix(self._stage_name)
|
|
51
|
+
|
|
52
|
+
def is_user_stage(self) -> bool:
|
|
53
|
+
return self._is_user_stage
|
|
54
|
+
|
|
55
|
+
def is_git_repo(self) -> bool:
|
|
56
|
+
return self._is_git_repo
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def git_ref(self) -> str | None:
|
|
60
|
+
return self._git_ref
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def add_at_prefix(text: str):
|
|
64
|
+
if not text.startswith("@"):
|
|
65
|
+
return "@" + text
|
|
66
|
+
return text
|
|
67
|
+
|
|
68
|
+
@staticmethod
|
|
69
|
+
def strip_at_prefix(text: str):
|
|
70
|
+
if text.startswith("@"):
|
|
71
|
+
return text[1:]
|
|
72
|
+
return text
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
def strip_snow_prefix(text: str):
|
|
76
|
+
if text.startswith("snow://"):
|
|
77
|
+
return text[len("snow://") :]
|
|
78
|
+
return text
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
def strip_stage_prefixes(cls, text: str):
|
|
82
|
+
return cls.strip_at_prefix(cls.strip_snow_prefix(text))
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def from_stage_str(cls, stage_str: str | FQN):
|
|
86
|
+
stage_str = cls.strip_stage_prefixes(str(stage_str))
|
|
87
|
+
parts = stage_str.split("/", maxsplit=1)
|
|
88
|
+
parts = [p for p in parts if p]
|
|
89
|
+
if len(parts) == 2:
|
|
90
|
+
stage_string, path = parts
|
|
91
|
+
else:
|
|
92
|
+
stage_string = parts[0]
|
|
93
|
+
path = None
|
|
94
|
+
return cls(
|
|
95
|
+
stage_name=stage_string, path=path, trailing_slash=stage_str.endswith("/")
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
@classmethod
|
|
99
|
+
def from_git_str(cls, git_str: str):
|
|
100
|
+
"""
|
|
101
|
+
@configuration_repo / branches/main / scripts/setup.sql
|
|
102
|
+
@configuration_repo / branches/"foo/main" / scripts/setup.sql
|
|
103
|
+
"""
|
|
104
|
+
repo_name, git_ref, path = cls._split_repo_path(
|
|
105
|
+
cls.strip_stage_prefixes(git_str)
|
|
106
|
+
)
|
|
107
|
+
return cls(
|
|
108
|
+
stage_name=repo_name,
|
|
109
|
+
path=path,
|
|
110
|
+
git_ref=git_ref,
|
|
111
|
+
trailing_slash=git_str.endswith("/"),
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
@staticmethod
|
|
115
|
+
def _split_repo_path(git_str: str) -> tuple[str, str, str]:
|
|
116
|
+
parts = []
|
|
117
|
+
slash_index = 0
|
|
118
|
+
skipping_mode = False
|
|
119
|
+
for current_idx, (char, next_char) in enumerate(zip(git_str[:-1], git_str[1:])):
|
|
120
|
+
if not skipping_mode:
|
|
121
|
+
if char != "/":
|
|
122
|
+
continue
|
|
123
|
+
|
|
124
|
+
# Normal split
|
|
125
|
+
parts.append(git_str[slash_index:current_idx])
|
|
126
|
+
slash_index = current_idx + 1
|
|
127
|
+
|
|
128
|
+
if next_char == '"':
|
|
129
|
+
skipping_mode = not skipping_mode
|
|
130
|
+
# Add last part
|
|
131
|
+
parts.append(git_str[slash_index:])
|
|
132
|
+
repo_name = parts[0]
|
|
133
|
+
ref = parts[1] + "/" + parts[2]
|
|
134
|
+
path = "/".join(parts[3:]) if len(parts) > 2 else ""
|
|
135
|
+
return repo_name, ref, path
|
|
136
|
+
|
|
137
|
+
def absolute_path(self, no_fqn=False, at_prefix=True) -> str:
|
|
138
|
+
stage_name = self._stage_name
|
|
139
|
+
if not self.is_user_stage() and no_fqn:
|
|
140
|
+
stage_name = FQN.from_string(self._stage_name).name
|
|
141
|
+
|
|
142
|
+
path = PurePosixPath(stage_name)
|
|
143
|
+
if self.git_ref:
|
|
144
|
+
path = path / self.git_ref
|
|
145
|
+
if not self.is_root():
|
|
146
|
+
path = path / self._path
|
|
147
|
+
|
|
148
|
+
str_path = str(path)
|
|
149
|
+
if at_prefix:
|
|
150
|
+
str_path = self.add_at_prefix(str_path)
|
|
151
|
+
|
|
152
|
+
if self._trailing_slash:
|
|
153
|
+
return str_path.rstrip("/") + "/"
|
|
154
|
+
return str_path
|
|
155
|
+
|
|
156
|
+
def joinpath(self, path: str) -> StagePath:
|
|
157
|
+
if self.is_file():
|
|
158
|
+
raise ValueError("Cannot join path to a file")
|
|
159
|
+
|
|
160
|
+
return StagePath(
|
|
161
|
+
stage_name=self._stage_name,
|
|
162
|
+
path=PurePosixPath(self._path) / path.lstrip("/"),
|
|
163
|
+
git_ref=self._git_ref,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
def __truediv__(self, path: str):
|
|
167
|
+
return self.joinpath(path)
|
|
168
|
+
|
|
169
|
+
def with_stage(self, stage_name: str) -> StagePath:
|
|
170
|
+
"""Returns a new path with new stage name"""
|
|
171
|
+
return StagePath(
|
|
172
|
+
stage_name=stage_name,
|
|
173
|
+
path=self._path,
|
|
174
|
+
git_ref=self._git_ref,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
@property
|
|
178
|
+
def parts(self) -> tuple[str, ...]:
|
|
179
|
+
return self._path.parts
|
|
180
|
+
|
|
181
|
+
@property
|
|
182
|
+
def name(self) -> str:
|
|
183
|
+
return self._path.name
|
|
184
|
+
|
|
185
|
+
def is_dir(self) -> bool:
|
|
186
|
+
return "." not in self.name
|
|
187
|
+
|
|
188
|
+
def is_file(self) -> bool:
|
|
189
|
+
return not self.is_dir()
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def suffix(self) -> str:
|
|
193
|
+
return self._path.suffix
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def stem(self) -> str:
|
|
197
|
+
return self._path.stem
|
|
198
|
+
|
|
199
|
+
@property
|
|
200
|
+
def parent(self) -> StagePath:
|
|
201
|
+
return StagePath(
|
|
202
|
+
stage_name=self._stage_name, path=self._path.parent, git_ref=self._git_ref
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
def is_root(self) -> bool:
|
|
206
|
+
return self._path == PurePosixPath(".")
|
|
207
|
+
|
|
208
|
+
def root_path(self) -> StagePath:
|
|
209
|
+
if self.is_git_repo():
|
|
210
|
+
return StagePath(stage_name=self._stage_name, git_ref=self._git_ref)
|
|
211
|
+
return StagePath(stage_name=self._stage_name)
|
|
212
|
+
|
|
213
|
+
def is_quoted(self) -> bool:
|
|
214
|
+
path = self.absolute_path()
|
|
215
|
+
return path.startswith("'") and path.endswith("'")
|
|
216
|
+
|
|
217
|
+
def path_for_sql(self) -> str:
|
|
218
|
+
path = self.absolute_path()
|
|
219
|
+
if not re.fullmatch(r"@([\w./$])+", path):
|
|
220
|
+
return to_string_literal(path)
|
|
221
|
+
return path
|
|
222
|
+
|
|
223
|
+
def quoted_absolute_path(self) -> str:
|
|
224
|
+
if self.is_quoted():
|
|
225
|
+
return self.absolute_path()
|
|
226
|
+
return to_string_literal(self.absolute_path())
|
|
227
|
+
|
|
228
|
+
def relative_to(self, stage_path: StagePath) -> PurePosixPath:
|
|
229
|
+
return self.path.relative_to(stage_path.path)
|
|
230
|
+
|
|
231
|
+
def get_local_target_path(self, target_dir: Path, stage_root: StagePath):
|
|
232
|
+
# Case for downloading @stage/aa/file.py with root @stage/aa
|
|
233
|
+
if self.relative_to(stage_root) == PurePosixPath("."):
|
|
234
|
+
return target_dir
|
|
235
|
+
return (target_dir / self.relative_to(stage_root)).parent
|
|
236
|
+
|
|
237
|
+
def __str__(self):
|
|
238
|
+
return self.absolute_path()
|
|
239
|
+
|
|
240
|
+
def __eq__(self, other):
|
|
241
|
+
return self.absolute_path() == other.absolute_path()
|
|
@@ -285,9 +285,7 @@ def _add_defaults_to_definition(original_definition: Definition) -> Definition:
|
|
|
285
285
|
with context({"skip_validation_on_templates": True}):
|
|
286
286
|
# pass a flag to Pydantic to skip validation for templated scalars
|
|
287
287
|
# populate the defaults
|
|
288
|
-
project_definition = build_project_definition(
|
|
289
|
-
**copy.deepcopy(original_definition)
|
|
290
|
-
)
|
|
288
|
+
project_definition = build_project_definition(**original_definition)
|
|
291
289
|
|
|
292
290
|
definition_with_defaults = project_definition.model_dump(
|
|
293
291
|
exclude_none=True, warnings=False, by_alias=True
|
|
@@ -392,8 +390,8 @@ def render_definition_template(
|
|
|
392
390
|
definition,
|
|
393
391
|
update_action=lambda val: template_env.render(val, final_context),
|
|
394
392
|
)
|
|
395
|
-
|
|
396
|
-
|
|
393
|
+
with context({"is_duplicated_run": True}):
|
|
394
|
+
project_definition = build_project_definition(**definition)
|
|
397
395
|
|
|
398
396
|
# Use the values originally provided by the user as the template context
|
|
399
397
|
# This intentionally doesn't reflect any field changes made by
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: snowflake-cli
|
|
3
|
-
Version: 3.0
|
|
3
|
+
Version: 3.1.0
|
|
4
4
|
Summary: Snowflake CLI
|
|
5
5
|
Project-URL: Source code, https://github.com/snowflakedb/snowflake-cli
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/snowflakedb/snowflake-cli/issues
|
|
@@ -226,7 +226,7 @@ Requires-Dist: pydantic==2.9.2
|
|
|
226
226
|
Requires-Dist: pyyaml==6.0.2
|
|
227
227
|
Requires-Dist: requests==2.32.3
|
|
228
228
|
Requires-Dist: requirements-parser==0.11.0
|
|
229
|
-
Requires-Dist: rich==13.
|
|
229
|
+
Requires-Dist: rich==13.9.2
|
|
230
230
|
Requires-Dist: setuptools==75.1.0
|
|
231
231
|
Requires-Dist: snowflake-connector-python[secure-local-storage]==3.12.2
|
|
232
232
|
Requires-Dist: snowflake-core==0.12.1; python_version < '3.12'
|
|
@@ -235,11 +235,13 @@ Requires-Dist: tomlkit==0.13.2
|
|
|
235
235
|
Requires-Dist: typer==0.12.5
|
|
236
236
|
Requires-Dist: urllib3<2.3,>=1.24.3
|
|
237
237
|
Provides-Extra: development
|
|
238
|
-
Requires-Dist: coverage==7.6.
|
|
238
|
+
Requires-Dist: coverage==7.6.3; extra == 'development'
|
|
239
|
+
Requires-Dist: factory-boy==3.3.1; extra == 'development'
|
|
240
|
+
Requires-Dist: faker==30.3.0; extra == 'development'
|
|
239
241
|
Requires-Dist: pre-commit>=3.5.0; extra == 'development'
|
|
240
242
|
Requires-Dist: pytest-randomly==3.15.0; extra == 'development'
|
|
241
243
|
Requires-Dist: pytest==8.3.3; extra == 'development'
|
|
242
|
-
Requires-Dist: syrupy==4.7.
|
|
244
|
+
Requires-Dist: syrupy==4.7.2; extra == 'development'
|
|
243
245
|
Provides-Extra: packaging
|
|
244
246
|
Requires-Dist: pyinstaller~=6.10; extra == 'packaging'
|
|
245
247
|
Description-Content-Type: text/markdown
|
|
@@ -272,15 +274,13 @@ Snowflake CLI is an open-source command-line tool explicitly designed for develo
|
|
|
272
274
|
|
|
273
275
|
With Snowflake CLI, developers can create, manage, update, and view apps running on Snowflake across workloads such as Streamlit in Snowflake, the Snowflake Native App Framework, Snowpark Container Services, and Snowpark. It supports a range of Snowflake features, including user-defined functions, stored procedures, Streamlit in Snowflake, and SQL execution.
|
|
274
276
|
|
|
275
|
-
|
|
276
277
|
**Note**: Snowflake CLI is in Public Preview (PuPr).
|
|
277
278
|
|
|
278
|
-
Docs: https://docs.snowflake.com/en/developer-guide/snowflake-cli-v2/index
|
|
279
|
-
|
|
280
|
-
Quick start: https://quickstarts.snowflake.com/guide/getting-started-with-snowflake-cli
|
|
279
|
+
Docs: <https://docs.snowflake.com/en/developer-guide/snowflake-cli-v2/index>.
|
|
281
280
|
|
|
282
|
-
|
|
281
|
+
Quick start: <https://quickstarts.snowflake.com/guide/getting-started-with-snowflake-cli>
|
|
283
282
|
|
|
283
|
+
Cheatsheet: <https://github.com/Snowflake-Labs/sf-cheatsheets/blob/main/snowflake-cli.md>
|
|
284
284
|
|
|
285
285
|
## Install Snowflake CLI
|
|
286
286
|
|
|
@@ -289,7 +289,7 @@ Cheatsheet: https://github.com/Snowflake-Labs/sf-cheatsheets/blob/main/snowflake
|
|
|
289
289
|
We recommend installing Snowflake CLI in isolated environment using [pipx](https://pipx.pypa.io/stable/). Requires Python >= 3.10
|
|
290
290
|
|
|
291
291
|
```bash
|
|
292
|
-
pipx install snowflake-cli
|
|
292
|
+
pipx install snowflake-cli
|
|
293
293
|
snow --help
|
|
294
294
|
```
|
|
295
295
|
|
|
@@ -322,4 +322,4 @@ You should now be able to run `snow` and get the CLI message.
|
|
|
322
322
|
## Get involved
|
|
323
323
|
|
|
324
324
|
Have a feature idea? Running into a bug? Want to contribute? We'd love to hear from you!
|
|
325
|
-
Please open or review issues, open pull requests, or reach out to us on developers@snowflake.com
|
|
325
|
+
Please open or review issues, open pull requests, or reach out to us on <developers@snowflake.com>
|