snowflake-cli-labs 2.6.0rc0__py3-none-any.whl → 2.7.0rc0__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/api/cli_global_context.py +9 -0
- snowflake/cli/api/commands/decorators.py +9 -4
- snowflake/cli/api/commands/execution_metadata.py +40 -0
- snowflake/cli/api/commands/flags.py +45 -36
- snowflake/cli/api/commands/project_initialisation.py +4 -1
- snowflake/cli/api/commands/snow_typer.py +20 -9
- snowflake/cli/api/config.py +3 -0
- snowflake/cli/api/errno.py +27 -0
- snowflake/cli/api/feature_flags.py +1 -0
- snowflake/cli/api/identifiers.py +20 -3
- snowflake/cli/api/output/types.py +9 -0
- snowflake/cli/api/project/definition_manager.py +2 -2
- snowflake/cli/api/project/project_verification.py +23 -0
- snowflake/cli/api/project/schemas/entities/application_entity.py +50 -0
- snowflake/cli/api/project/schemas/entities/application_package_entity.py +63 -0
- snowflake/cli/api/project/schemas/entities/common.py +85 -0
- snowflake/cli/api/project/schemas/entities/entities.py +30 -0
- snowflake/cli/api/project/schemas/project_definition.py +114 -22
- snowflake/cli/api/project/schemas/streamlit/streamlit.py +5 -4
- snowflake/cli/api/project/schemas/template.py +77 -0
- snowflake/cli/{plugins/nativeapp/errno.py → api/rendering/__init__.py} +0 -2
- snowflake/cli/api/{utils/rendering.py → rendering/jinja.py} +3 -48
- snowflake/cli/api/rendering/project_definition_templates.py +39 -0
- snowflake/cli/api/rendering/project_templates.py +97 -0
- snowflake/cli/api/rendering/sql_templates.py +56 -0
- snowflake/cli/api/rest_api.py +84 -25
- snowflake/cli/api/sql_execution.py +40 -1
- snowflake/cli/api/utils/definition_rendering.py +8 -5
- snowflake/cli/app/cli_app.py +0 -2
- snowflake/cli/app/commands_registration/builtin_plugins.py +4 -0
- snowflake/cli/app/dev/docs/project_definition_docs_generator.py +2 -2
- snowflake/cli/app/loggers.py +10 -6
- snowflake/cli/app/printing.py +17 -7
- snowflake/cli/app/snow_connector.py +9 -1
- snowflake/cli/app/telemetry.py +41 -2
- snowflake/cli/plugins/connection/commands.py +4 -3
- snowflake/cli/plugins/connection/util.py +73 -18
- snowflake/cli/plugins/cortex/commands.py +2 -1
- snowflake/cli/plugins/git/commands.py +20 -4
- snowflake/cli/plugins/git/manager.py +44 -20
- snowflake/cli/plugins/init/__init__.py +13 -0
- snowflake/cli/plugins/init/commands.py +242 -0
- snowflake/cli/plugins/init/plugin_spec.py +30 -0
- snowflake/cli/plugins/nativeapp/codegen/artifact_processor.py +40 -0
- snowflake/cli/plugins/nativeapp/codegen/compiler.py +57 -27
- snowflake/cli/plugins/nativeapp/codegen/sandbox.py +99 -10
- snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +172 -0
- snowflake/cli/plugins/nativeapp/codegen/setup/setup_driver.py.source +56 -0
- snowflake/cli/plugins/nativeapp/codegen/snowpark/python_processor.py +21 -21
- snowflake/cli/plugins/nativeapp/commands.py +69 -6
- snowflake/cli/plugins/nativeapp/constants.py +0 -6
- snowflake/cli/plugins/nativeapp/exceptions.py +37 -12
- snowflake/cli/plugins/nativeapp/init.py +1 -1
- snowflake/cli/plugins/nativeapp/manager.py +114 -39
- snowflake/cli/plugins/nativeapp/project_model.py +8 -4
- snowflake/cli/plugins/nativeapp/run_processor.py +117 -102
- snowflake/cli/plugins/nativeapp/teardown_processor.py +7 -2
- snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +146 -0
- snowflake/cli/plugins/nativeapp/version/commands.py +19 -3
- snowflake/cli/plugins/nativeapp/version/version_processor.py +11 -3
- snowflake/cli/plugins/object/commands.py +1 -1
- snowflake/cli/plugins/object/manager.py +2 -15
- snowflake/cli/plugins/snowpark/commands.py +34 -26
- snowflake/cli/plugins/snowpark/common.py +88 -27
- snowflake/cli/plugins/snowpark/manager.py +16 -5
- snowflake/cli/plugins/snowpark/models.py +6 -0
- snowflake/cli/plugins/sql/commands.py +3 -5
- snowflake/cli/plugins/sql/manager.py +1 -1
- snowflake/cli/plugins/stage/commands.py +2 -2
- snowflake/cli/plugins/stage/diff.py +4 -2
- snowflake/cli/plugins/stage/manager.py +290 -86
- snowflake/cli/plugins/streamlit/commands.py +20 -6
- snowflake/cli/plugins/streamlit/manager.py +29 -27
- snowflake/cli/plugins/workspace/__init__.py +13 -0
- snowflake/cli/plugins/workspace/commands.py +35 -0
- snowflake/cli/plugins/workspace/plugin_spec.py +30 -0
- snowflake/cli/templates/default_snowpark/app/__init__.py +0 -13
- snowflake/cli/templates/default_snowpark/app/common.py +0 -15
- snowflake/cli/templates/default_snowpark/app/functions.py +0 -14
- snowflake/cli/templates/default_snowpark/app/procedures.py +0 -14
- snowflake/cli/templates/default_streamlit/common/hello.py +0 -15
- snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -14
- snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -14
- {snowflake_cli_labs-2.6.0rc0.dist-info → snowflake_cli_labs-2.7.0rc0.dist-info}/METADATA +7 -6
- {snowflake_cli_labs-2.6.0rc0.dist-info → snowflake_cli_labs-2.7.0rc0.dist-info}/RECORD +89 -69
- {snowflake_cli_labs-2.6.0rc0.dist-info → snowflake_cli_labs-2.7.0rc0.dist-info}/WHEEL +0 -0
- {snowflake_cli_labs-2.6.0rc0.dist-info → snowflake_cli_labs-2.7.0rc0.dist-info}/entry_points.txt +0 -0
- {snowflake_cli_labs-2.6.0rc0.dist-info → snowflake_cli_labs-2.7.0rc0.dist-info}/licenses/LICENSE +0 -0
snowflake/cli/__about__.py
CHANGED
|
@@ -47,6 +47,7 @@ class _ConnectionContext:
|
|
|
47
47
|
self._temporary_connection: bool = False
|
|
48
48
|
self._session_token: Optional[str] = None
|
|
49
49
|
self._master_token: Optional[str] = None
|
|
50
|
+
self._token_file_path: Optional[Path] = None
|
|
50
51
|
|
|
51
52
|
def __setattr__(self, key, value):
|
|
52
53
|
"""
|
|
@@ -182,6 +183,13 @@ class _ConnectionContext:
|
|
|
182
183
|
def set_master_token(self, value: Optional[str]):
|
|
183
184
|
self._master_token = value
|
|
184
185
|
|
|
186
|
+
@property
|
|
187
|
+
def token_file_path(self) -> Optional[Path]:
|
|
188
|
+
return self._token_file_path
|
|
189
|
+
|
|
190
|
+
def set_token_file_path(self, value: Optional[Path]):
|
|
191
|
+
self._token_file_path = value
|
|
192
|
+
|
|
185
193
|
@property
|
|
186
194
|
def connection(self) -> SnowflakeConnection:
|
|
187
195
|
if not self._cached_connection:
|
|
@@ -201,6 +209,7 @@ class _ConnectionContext:
|
|
|
201
209
|
"warehouse": self.warehouse,
|
|
202
210
|
"session_token": self.session_token,
|
|
203
211
|
"master_token": self.master_token,
|
|
212
|
+
"token_file_path": self.token_file_path,
|
|
204
213
|
}
|
|
205
214
|
|
|
206
215
|
def _build_connection(self):
|
|
@@ -39,6 +39,7 @@ from snowflake.cli.api.commands.flags import (
|
|
|
39
39
|
SessionTokenOption,
|
|
40
40
|
SilentOption,
|
|
41
41
|
TemporaryConnectionOption,
|
|
42
|
+
TokenFilePathOption,
|
|
42
43
|
UserOption,
|
|
43
44
|
VerboseOption,
|
|
44
45
|
WarehouseOption,
|
|
@@ -73,9 +74,7 @@ def global_options_with_connection(func: Callable):
|
|
|
73
74
|
)
|
|
74
75
|
|
|
75
76
|
|
|
76
|
-
def with_project_definition(
|
|
77
|
-
project_name: Optional[str] = None, is_optional: bool = False
|
|
78
|
-
):
|
|
77
|
+
def with_project_definition(is_optional: bool = False):
|
|
79
78
|
def _decorator(func: Callable):
|
|
80
79
|
|
|
81
80
|
return _options_decorator_factory(
|
|
@@ -85,7 +84,7 @@ def with_project_definition(
|
|
|
85
84
|
"project_definition",
|
|
86
85
|
inspect.Parameter.KEYWORD_ONLY,
|
|
87
86
|
annotation=Optional[str],
|
|
88
|
-
default=project_definition_option(
|
|
87
|
+
default=project_definition_option(is_optional),
|
|
89
88
|
),
|
|
90
89
|
inspect.Parameter(
|
|
91
90
|
"env_overrides",
|
|
@@ -252,6 +251,12 @@ GLOBAL_CONNECTION_OPTIONS = [
|
|
|
252
251
|
annotation=Optional[str],
|
|
253
252
|
default=MasterTokenOption,
|
|
254
253
|
),
|
|
254
|
+
inspect.Parameter(
|
|
255
|
+
"token_file_path",
|
|
256
|
+
inspect.Parameter.KEYWORD_ONLY,
|
|
257
|
+
annotation=Optional[str],
|
|
258
|
+
default=TokenFilePathOption,
|
|
259
|
+
),
|
|
255
260
|
inspect.Parameter(
|
|
256
261
|
"database",
|
|
257
262
|
inspect.Parameter.KEYWORD_ONLY,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
import time
|
|
15
|
+
import uuid
|
|
16
|
+
from dataclasses import dataclass, field
|
|
17
|
+
from enum import Enum
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ExecutionStatus(Enum):
|
|
21
|
+
SUCCESS = "success"
|
|
22
|
+
FAILURE = "failure"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class ExecutionMetadata:
|
|
27
|
+
start_time: float = 0.0
|
|
28
|
+
end_time: float = 0.0
|
|
29
|
+
status: ExecutionStatus = ExecutionStatus.SUCCESS
|
|
30
|
+
execution_id: str = field(default_factory=lambda: uuid.uuid4().hex)
|
|
31
|
+
|
|
32
|
+
def __post_init__(self):
|
|
33
|
+
self.start_time = time.monotonic()
|
|
34
|
+
|
|
35
|
+
def complete(self, status: ExecutionStatus):
|
|
36
|
+
self.end_time = time.monotonic()
|
|
37
|
+
self.status = status
|
|
38
|
+
|
|
39
|
+
def get_duration(self):
|
|
40
|
+
return self.end_time - self.start_time
|
|
@@ -27,10 +27,10 @@ from click import ClickException
|
|
|
27
27
|
from snowflake.cli.api.cli_global_context import cli_context_manager
|
|
28
28
|
from snowflake.cli.api.commands.typer_pre_execute import register_pre_execute_command
|
|
29
29
|
from snowflake.cli.api.console import cli_console
|
|
30
|
-
from snowflake.cli.api.exceptions import MissingConfiguration
|
|
30
|
+
from snowflake.cli.api.exceptions import MissingConfiguration
|
|
31
31
|
from snowflake.cli.api.output.formats import OutputFormat
|
|
32
32
|
from snowflake.cli.api.project.definition_manager import DefinitionManager
|
|
33
|
-
from snowflake.cli.api.
|
|
33
|
+
from snowflake.cli.api.rendering.jinja import CONTEXT_KEY
|
|
34
34
|
|
|
35
35
|
DEFAULT_CONTEXT_SETTINGS = {"help_option_names": ["--help", "-h"]}
|
|
36
36
|
|
|
@@ -140,6 +140,9 @@ class OverrideableOption:
|
|
|
140
140
|
return generated_callback
|
|
141
141
|
|
|
142
142
|
|
|
143
|
+
from snowflake.cli.api.config import get_all_connections
|
|
144
|
+
|
|
145
|
+
|
|
143
146
|
def _callback(provide_setter: Callable[[], Callable[[Any], Any]]):
|
|
144
147
|
def callback(value):
|
|
145
148
|
set_value = provide_setter()
|
|
@@ -160,6 +163,7 @@ ConnectionOption = typer.Option(
|
|
|
160
163
|
),
|
|
161
164
|
show_default=False,
|
|
162
165
|
rich_help_panel=_CONNECTION_SECTION,
|
|
166
|
+
autocompletion=lambda: list(get_all_connections()),
|
|
163
167
|
)
|
|
164
168
|
|
|
165
169
|
TemporaryConnectionOption = typer.Option(
|
|
@@ -272,6 +276,20 @@ MasterTokenOption = typer.Option(
|
|
|
272
276
|
hidden=True,
|
|
273
277
|
)
|
|
274
278
|
|
|
279
|
+
TokenFilePathOption = typer.Option(
|
|
280
|
+
None,
|
|
281
|
+
"--token-file-path",
|
|
282
|
+
help="Path to file with an OAuth token that should be used when connecting to Snowflake",
|
|
283
|
+
callback=_callback(
|
|
284
|
+
lambda: cli_context_manager.connection_context.set_token_file_path
|
|
285
|
+
),
|
|
286
|
+
show_default=False,
|
|
287
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
288
|
+
exists=True,
|
|
289
|
+
file_okay=True,
|
|
290
|
+
dir_okay=False,
|
|
291
|
+
)
|
|
292
|
+
|
|
275
293
|
DatabaseOption = typer.Option(
|
|
276
294
|
None,
|
|
277
295
|
"--database",
|
|
@@ -429,12 +447,24 @@ OnErrorOption = typer.Option(
|
|
|
429
447
|
help="What to do when an error occurs. Defaults to break.",
|
|
430
448
|
)
|
|
431
449
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
450
|
+
NoInteractiveOption = typer.Option(False, "--no-interactive", help="Disable prompting.")
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def variables_option(description: str):
|
|
454
|
+
return typer.Option(
|
|
455
|
+
None,
|
|
456
|
+
"--variable",
|
|
457
|
+
"-D",
|
|
458
|
+
help=description,
|
|
459
|
+
show_default=False,
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
ExecuteVariablesOption = variables_option(
|
|
464
|
+
'Variables for the execution context. For example: `-D "<key>=<value>"`. '
|
|
465
|
+
"For SQL files variables are use to expand the template and any unknown variable will cause an error. "
|
|
466
|
+
"For Python files variables are used to update os.environ dictionary. Provided keys are capitalized to adhere to best practices."
|
|
467
|
+
"In case of SQL files string values must be quoted in `''` (consider embedding quoting in the file).",
|
|
438
468
|
)
|
|
439
469
|
|
|
440
470
|
|
|
@@ -500,7 +530,7 @@ def execution_identifier_argument(sf_object: str, example: str) -> typer.Argumen
|
|
|
500
530
|
)
|
|
501
531
|
|
|
502
532
|
|
|
503
|
-
def register_project_definition(
|
|
533
|
+
def register_project_definition(is_optional: bool) -> None:
|
|
504
534
|
project_path = cli_context_manager.project_path_arg
|
|
505
535
|
env_overrides_args = cli_context_manager.project_env_overrides_args
|
|
506
536
|
|
|
@@ -514,42 +544,21 @@ def register_project_definition(project_name: Optional[str], is_optional: bool)
|
|
|
514
544
|
"Cannot find project definition (snowflake.yml). Please provide a path to the project or run this command in a valid project directory."
|
|
515
545
|
)
|
|
516
546
|
|
|
517
|
-
if project_name is not None and not getattr(project_definition, project_name, None):
|
|
518
|
-
raise NoProjectDefinitionError(
|
|
519
|
-
project_type=project_name, project_file=project_path
|
|
520
|
-
)
|
|
521
|
-
|
|
522
547
|
cli_context_manager.set_project_definition(project_definition)
|
|
523
548
|
cli_context_manager.set_project_root(project_root)
|
|
524
549
|
cli_context_manager.set_template_context(template_context)
|
|
525
550
|
|
|
526
551
|
|
|
527
|
-
def
|
|
528
|
-
if project_short_name is None:
|
|
529
|
-
return "Snowflake"
|
|
530
|
-
|
|
531
|
-
if project_short_name == "native_app":
|
|
532
|
-
project_long_name = "Snowflake Native App"
|
|
533
|
-
elif project_short_name == "streamlit":
|
|
534
|
-
project_long_name = "Streamlit app"
|
|
535
|
-
else:
|
|
536
|
-
project_long_name = project_short_name.replace("_", " ").capitalize()
|
|
537
|
-
|
|
538
|
-
return f"the {project_long_name}"
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
def project_definition_option(project_name: Optional[str], is_optional: bool):
|
|
552
|
+
def project_definition_option(is_optional: bool):
|
|
542
553
|
def project_definition_callback(project_path: str) -> None:
|
|
543
554
|
cli_context_manager.set_project_path_arg(project_path)
|
|
544
|
-
register_pre_execute_command(
|
|
545
|
-
lambda: register_project_definition(project_name, is_optional)
|
|
546
|
-
)
|
|
555
|
+
register_pre_execute_command(lambda: register_project_definition(is_optional))
|
|
547
556
|
|
|
548
557
|
return typer.Option(
|
|
549
558
|
None,
|
|
550
559
|
"-p",
|
|
551
560
|
"--project",
|
|
552
|
-
help=f"Path where
|
|
561
|
+
help=f"Path where Snowflake project resides. "
|
|
553
562
|
f"Defaults to current working directory.",
|
|
554
563
|
callback=_callback(lambda: project_definition_callback),
|
|
555
564
|
show_default=False,
|
|
@@ -617,11 +626,11 @@ class Variable:
|
|
|
617
626
|
|
|
618
627
|
def parse_key_value_variables(variables: Optional[List[str]]) -> List[Variable]:
|
|
619
628
|
"""Util for parsing key=value input. Useful for commands accepting multiple input options."""
|
|
629
|
+
if not variables:
|
|
630
|
+
return []
|
|
620
631
|
result: List[Variable] = []
|
|
621
|
-
|
|
622
|
-
if variables is None:
|
|
632
|
+
if not variables:
|
|
623
633
|
return result
|
|
624
|
-
|
|
625
634
|
for p in variables:
|
|
626
635
|
if "=" not in p:
|
|
627
636
|
raise ClickException(f"Invalid variable: '{p}'")
|
|
@@ -35,7 +35,7 @@ def add_init_command(
|
|
|
35
35
|
template: str,
|
|
36
36
|
help_message: Optional[str] = None,
|
|
37
37
|
):
|
|
38
|
-
@app.command()
|
|
38
|
+
@app.command(deprecated=True)
|
|
39
39
|
def init(
|
|
40
40
|
project_name: str = Argument(
|
|
41
41
|
f"example_{project_type.lower()}",
|
|
@@ -47,6 +47,7 @@ def add_init_command(
|
|
|
47
47
|
),
|
|
48
48
|
**options,
|
|
49
49
|
) -> CommandResult:
|
|
50
|
+
|
|
50
51
|
_create_project_template(template, project_directory=project_name)
|
|
51
52
|
return MessageResult(f"Initialized the new project in {project_name}/")
|
|
52
53
|
|
|
@@ -57,6 +58,8 @@ def add_init_command(
|
|
|
57
58
|
init.__doc__ = (
|
|
58
59
|
f"Initializes this directory with a sample set "
|
|
59
60
|
f"of files for creating a {project_type_doc} project."
|
|
61
|
+
f"This command is deprecated and will be removed soon."
|
|
62
|
+
f"Please use 'snow init' instead"
|
|
60
63
|
)
|
|
61
64
|
|
|
62
65
|
return init
|
|
@@ -24,6 +24,10 @@ from snowflake.cli.api.commands.decorators import (
|
|
|
24
24
|
global_options,
|
|
25
25
|
global_options_with_connection,
|
|
26
26
|
)
|
|
27
|
+
from snowflake.cli.api.commands.execution_metadata import (
|
|
28
|
+
ExecutionMetadata,
|
|
29
|
+
ExecutionStatus,
|
|
30
|
+
)
|
|
27
31
|
from snowflake.cli.api.commands.flags import DEFAULT_CONTEXT_SETTINGS
|
|
28
32
|
from snowflake.cli.api.commands.typer_pre_execute import run_pre_execute_commands
|
|
29
33
|
from snowflake.cli.api.exceptions import CommandReturnTypeError
|
|
@@ -91,15 +95,18 @@ class SnowTyper(typer.Typer):
|
|
|
91
95
|
@wraps(command_callable)
|
|
92
96
|
def command_callable_decorator(*args, **kw):
|
|
93
97
|
"""Wrapper around command callable. This is what happens at "runtime"."""
|
|
94
|
-
|
|
98
|
+
execution = ExecutionMetadata()
|
|
99
|
+
self.pre_execute(execution)
|
|
95
100
|
try:
|
|
96
101
|
result = command_callable(*args, **kw)
|
|
97
|
-
|
|
102
|
+
self.process_result(result)
|
|
103
|
+
execution.complete(ExecutionStatus.SUCCESS)
|
|
98
104
|
except Exception as err:
|
|
99
|
-
|
|
105
|
+
execution.complete(ExecutionStatus.FAILURE)
|
|
106
|
+
self.exception_handler(err, execution)
|
|
100
107
|
raise
|
|
101
108
|
finally:
|
|
102
|
-
self.post_execute()
|
|
109
|
+
self.post_execute(execution)
|
|
103
110
|
|
|
104
111
|
return super(SnowTyper, self).command(name=name, **kwargs)(
|
|
105
112
|
command_callable_decorator
|
|
@@ -108,7 +115,7 @@ class SnowTyper(typer.Typer):
|
|
|
108
115
|
return custom_command
|
|
109
116
|
|
|
110
117
|
@staticmethod
|
|
111
|
-
def pre_execute():
|
|
118
|
+
def pre_execute(execution: ExecutionMetadata):
|
|
112
119
|
"""
|
|
113
120
|
Callback executed before running any command callable (after context execution).
|
|
114
121
|
Pay attention to make this method safe to use if performed operations are not necessary
|
|
@@ -118,7 +125,7 @@ class SnowTyper(typer.Typer):
|
|
|
118
125
|
|
|
119
126
|
log.debug("Executing command pre execution callback")
|
|
120
127
|
run_pre_execute_commands()
|
|
121
|
-
log_command_usage()
|
|
128
|
+
log_command_usage(execution)
|
|
122
129
|
|
|
123
130
|
@staticmethod
|
|
124
131
|
def process_result(result):
|
|
@@ -134,21 +141,25 @@ class SnowTyper(typer.Typer):
|
|
|
134
141
|
print_result(result)
|
|
135
142
|
|
|
136
143
|
@staticmethod
|
|
137
|
-
def exception_handler(exception: Exception):
|
|
144
|
+
def exception_handler(exception: Exception, execution: ExecutionMetadata):
|
|
138
145
|
"""
|
|
139
146
|
Callback executed on command execution error.
|
|
140
147
|
"""
|
|
148
|
+
from snowflake.cli.app.telemetry import log_command_execution_error
|
|
149
|
+
|
|
141
150
|
log.debug("Executing command exception callback")
|
|
151
|
+
log_command_execution_error(exception, execution)
|
|
142
152
|
|
|
143
153
|
@staticmethod
|
|
144
|
-
def post_execute():
|
|
154
|
+
def post_execute(execution: ExecutionMetadata):
|
|
145
155
|
"""
|
|
146
156
|
Callback executed after running any command callable. Pay attention to make this method safe to
|
|
147
157
|
use if performed operations are not necessary for executing the command in proper way.
|
|
148
158
|
"""
|
|
149
|
-
from snowflake.cli.app.telemetry import flush_telemetry
|
|
159
|
+
from snowflake.cli.app.telemetry import flush_telemetry, log_command_result
|
|
150
160
|
|
|
151
161
|
log.debug("Executing command post execution callback")
|
|
162
|
+
log_command_result(execution)
|
|
152
163
|
flush_telemetry()
|
|
153
164
|
|
|
154
165
|
|
snowflake/cli/api/config.py
CHANGED
|
@@ -114,6 +114,8 @@ def config_init(config_file: Optional[Path]):
|
|
|
114
114
|
Initializes the app configuration. Config provided via cli flag takes precedence.
|
|
115
115
|
If config file does not exist we create an empty one.
|
|
116
116
|
"""
|
|
117
|
+
from snowflake.cli.app.loggers import create_initial_loggers
|
|
118
|
+
|
|
117
119
|
if config_file:
|
|
118
120
|
CONFIG_MANAGER.file_path = config_file
|
|
119
121
|
else:
|
|
@@ -121,6 +123,7 @@ def config_init(config_file: Optional[Path]):
|
|
|
121
123
|
if not CONFIG_MANAGER.file_path.exists():
|
|
122
124
|
_initialise_config(CONFIG_MANAGER.file_path)
|
|
123
125
|
_read_config_file()
|
|
126
|
+
create_initial_loggers()
|
|
124
127
|
|
|
125
128
|
|
|
126
129
|
def add_connection(name: str, connection_config: ConnectionConfig):
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# General errors
|
|
16
|
+
NO_WAREHOUSE_SELECTED_IN_SESSION = 606
|
|
17
|
+
|
|
18
|
+
DOES_NOT_EXIST_OR_NOT_AUTHORIZED = 2003
|
|
19
|
+
DOES_NOT_EXIST_OR_CANNOT_BE_PERFORMED = 2043
|
|
20
|
+
|
|
21
|
+
# Native Apps
|
|
22
|
+
CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION = 93044
|
|
23
|
+
CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES = 93045
|
|
24
|
+
ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS = 93046
|
|
25
|
+
NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS = 93055
|
|
26
|
+
APPLICATION_NO_LONGER_AVAILABLE = 93079
|
|
27
|
+
APPLICATION_OWNS_EXTERNAL_OBJECTS = 93128
|
snowflake/cli/api/identifiers.py
CHANGED
|
@@ -53,17 +53,27 @@ class FQN:
|
|
|
53
53
|
return self._name
|
|
54
54
|
|
|
55
55
|
@property
|
|
56
|
-
def
|
|
56
|
+
def prefix(self) -> str:
|
|
57
57
|
if self.database:
|
|
58
|
-
return f"{self.database}.{self.schema if self.schema else 'PUBLIC'}
|
|
58
|
+
return f"{self.database}.{self.schema if self.schema else 'PUBLIC'}"
|
|
59
59
|
if self.schema:
|
|
60
|
-
return f"{self.schema}
|
|
60
|
+
return f"{self.schema}"
|
|
61
|
+
return ""
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def identifier(self) -> str:
|
|
65
|
+
if self.prefix:
|
|
66
|
+
return f"{self.prefix}.{self.name}"
|
|
61
67
|
return self.name
|
|
62
68
|
|
|
63
69
|
@property
|
|
64
70
|
def url_identifier(self) -> str:
|
|
65
71
|
return ".".join(identifier_for_url(part) for part in self.identifier.split("."))
|
|
66
72
|
|
|
73
|
+
@property
|
|
74
|
+
def sql_identifier(self) -> str:
|
|
75
|
+
return f"IDENTIFIER('{self.identifier}')"
|
|
76
|
+
|
|
67
77
|
def __str__(self):
|
|
68
78
|
return self.identifier
|
|
69
79
|
|
|
@@ -92,6 +102,13 @@ class FQN:
|
|
|
92
102
|
unqualified_name = unqualified_name + signature
|
|
93
103
|
return cls(name=unqualified_name, schema=schema, database=database)
|
|
94
104
|
|
|
105
|
+
@classmethod
|
|
106
|
+
def from_stage(cls, stage: str) -> "FQN":
|
|
107
|
+
name = stage
|
|
108
|
+
if stage.startswith("@"):
|
|
109
|
+
name = stage[1:]
|
|
110
|
+
return cls.from_string(name)
|
|
111
|
+
|
|
95
112
|
@classmethod
|
|
96
113
|
def from_identifier_model(cls, model: ObjectIdentifierBaseModel) -> "FQN":
|
|
97
114
|
"""Create an instance from object model."""
|
|
@@ -57,6 +57,15 @@ class MultipleResults(CommandResult):
|
|
|
57
57
|
return (element for element in self._elements)
|
|
58
58
|
|
|
59
59
|
|
|
60
|
+
class StreamResult(CommandResult):
|
|
61
|
+
def __init__(self, generator: t.Generator[CommandResult, None, None]):
|
|
62
|
+
self._generator = generator
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def result(self):
|
|
66
|
+
return self._generator
|
|
67
|
+
|
|
68
|
+
|
|
60
69
|
class QueryResult(CollectionResult):
|
|
61
70
|
def __init__(self, cursor: SnowflakeCursor | DictCursor):
|
|
62
71
|
self.column_names = [col.name for col in cursor.description]
|
|
@@ -20,7 +20,7 @@ from pathlib import Path
|
|
|
20
20
|
from typing import List, Optional
|
|
21
21
|
|
|
22
22
|
from snowflake.cli.api.project.definition import ProjectProperties, load_project
|
|
23
|
-
from snowflake.cli.api.project.schemas.project_definition import
|
|
23
|
+
from snowflake.cli.api.project.schemas.project_definition import ProjectDefinitionV1
|
|
24
24
|
from snowflake.cli.api.utils.types import Context
|
|
25
25
|
|
|
26
26
|
|
|
@@ -126,7 +126,7 @@ class DefinitionManager:
|
|
|
126
126
|
return load_project(self._project_config_paths, self._context_overrides)
|
|
127
127
|
|
|
128
128
|
@functools.cached_property
|
|
129
|
-
def project_definition(self) ->
|
|
129
|
+
def project_definition(self) -> ProjectDefinitionV1:
|
|
130
130
|
return self._project_properties.project_definition
|
|
131
131
|
|
|
132
132
|
@functools.cached_property
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from snowflake.cli.api.cli_global_context import cli_context
|
|
16
|
+
from snowflake.cli.api.exceptions import NoProjectDefinitionError
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def assert_project_type(project_type: str):
|
|
20
|
+
if not getattr(cli_context.project_definition, project_type, None):
|
|
21
|
+
raise NoProjectDefinitionError(
|
|
22
|
+
project_type=project_type, project_file=cli_context.project_root
|
|
23
|
+
)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import Literal, Optional
|
|
18
|
+
|
|
19
|
+
from pydantic import AliasChoices, Field
|
|
20
|
+
from snowflake.cli.api.project.schemas.entities.application_package_entity import (
|
|
21
|
+
ApplicationPackageEntity,
|
|
22
|
+
)
|
|
23
|
+
from snowflake.cli.api.project.schemas.entities.common import (
|
|
24
|
+
EntityBase,
|
|
25
|
+
TargetField,
|
|
26
|
+
)
|
|
27
|
+
from snowflake.cli.api.project.schemas.updatable_model import (
|
|
28
|
+
UpdatableModel,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ApplicationEntity(EntityBase):
|
|
33
|
+
type: Literal["application"] # noqa: A003
|
|
34
|
+
name: str = Field(
|
|
35
|
+
title="Name of the application created when this entity is deployed"
|
|
36
|
+
)
|
|
37
|
+
from_: ApplicationFromField = Field(
|
|
38
|
+
validation_alias=AliasChoices("from"),
|
|
39
|
+
title="An application package this entity should be created from",
|
|
40
|
+
)
|
|
41
|
+
debug: Optional[bool] = Field(
|
|
42
|
+
title="Whether to enable debug mode when using a named stage to create an application object",
|
|
43
|
+
default=None,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ApplicationFromField(UpdatableModel):
|
|
48
|
+
target: TargetField[ApplicationPackageEntity] = Field(
|
|
49
|
+
title="Reference to an application package entity",
|
|
50
|
+
)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import List, Literal, Optional, Union
|
|
19
|
+
|
|
20
|
+
from pydantic import Field
|
|
21
|
+
from snowflake.cli.api.project.schemas.entities.common import (
|
|
22
|
+
EntityBase,
|
|
23
|
+
)
|
|
24
|
+
from snowflake.cli.api.project.schemas.native_app.package import DistributionOptions
|
|
25
|
+
from snowflake.cli.api.project.schemas.native_app.path_mapping import PathMapping
|
|
26
|
+
from snowflake.cli.api.project.schemas.updatable_model import IdentifierField
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ApplicationPackageEntity(EntityBase):
|
|
30
|
+
type: Literal["application package"] # noqa: A003
|
|
31
|
+
name: str = Field(
|
|
32
|
+
title="Name of the application package created when this entity is deployed"
|
|
33
|
+
)
|
|
34
|
+
artifacts: List[Union[PathMapping, Path]] = Field(
|
|
35
|
+
title="List of paths or file source/destination pairs to add to the deploy root",
|
|
36
|
+
)
|
|
37
|
+
bundle_root: Optional[Path] = Field(
|
|
38
|
+
title="Folder at the root of your project where artifacts necessary to perform the bundle step are stored.",
|
|
39
|
+
default=Path("output/bundle/"),
|
|
40
|
+
)
|
|
41
|
+
deploy_root: Optional[Path] = Field(
|
|
42
|
+
title="Folder at the root of your project where the build step copies the artifacts",
|
|
43
|
+
default=Path("output/deploy/"),
|
|
44
|
+
)
|
|
45
|
+
generated_root: Optional[Path] = Field(
|
|
46
|
+
title="Subdirectory of the deploy root where files generated by the Snowflake CLI will be written.",
|
|
47
|
+
default=Path("__generated/"),
|
|
48
|
+
)
|
|
49
|
+
stage: Optional[str] = IdentifierField(
|
|
50
|
+
title="Identifier of the stage that stores the application artifacts.",
|
|
51
|
+
default="app_src.stage",
|
|
52
|
+
)
|
|
53
|
+
scratch_stage: Optional[str] = IdentifierField(
|
|
54
|
+
title="Identifier of the stage that stores temporary scratch data used by the Snowflake CLI.",
|
|
55
|
+
default="app_src.stage_snowflake_cli_scratch",
|
|
56
|
+
)
|
|
57
|
+
distribution: Optional[DistributionOptions] = Field(
|
|
58
|
+
title="Distribution of the application package created by the Snowflake CLI",
|
|
59
|
+
default="internal",
|
|
60
|
+
)
|
|
61
|
+
manifest: Path = Field(
|
|
62
|
+
title="Path to manifest.yml",
|
|
63
|
+
)
|