snowflake-cli-labs 2.8.0rc0__py3-none-any.whl → 3.0.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/{app → _app}/__main__.py +1 -1
- snowflake/cli/{app → _app}/cli_app.py +12 -12
- snowflake/cli/{app → _app}/commands_registration/builtin_plugins.py +13 -19
- snowflake/cli/{app → _app}/commands_registration/command_plugins_loader.py +9 -9
- snowflake/cli/{app → _app}/commands_registration/commands_registration_with_callbacks.py +4 -4
- snowflake/cli/{app → _app}/commands_registration/exception_logging.py +2 -2
- snowflake/cli/{app → _app}/commands_registration/typer_registration.py +2 -2
- snowflake/cli/{app → _app}/dev/docs/commands_docs_generator.py +30 -12
- snowflake/cli/{app → _app}/dev/docs/generator.py +3 -3
- snowflake/cli/{app → _app}/dev/docs/project_definition_docs_generator.py +4 -4
- snowflake/cli/{app → _app}/dev/docs/templates/usage.rst.jinja2 +14 -4
- snowflake/cli/{app → _app}/main_typer.py +2 -2
- snowflake/cli/{app → _app}/printing.py +2 -2
- snowflake/cli/{app → _app}/snow_connector.py +6 -6
- snowflake/cli/{app → _app}/telemetry.py +4 -5
- snowflake/cli/{plugins → _plugins}/connection/commands.py +22 -5
- snowflake/cli/_plugins/connection/plugin_spec.py +30 -0
- snowflake/cli/{plugins → _plugins}/connection/util.py +16 -0
- snowflake/cli/{plugins → _plugins}/cortex/commands.py +54 -49
- snowflake/cli/{plugins → _plugins}/cortex/constants.py +1 -1
- snowflake/cli/{plugins → _plugins}/cortex/manager.py +5 -5
- snowflake/cli/{plugins → _plugins}/cortex/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/git/commands.py +32 -20
- snowflake/cli/{plugins → _plugins}/git/manager.py +6 -5
- snowflake/cli/{plugins → _plugins}/git/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/init/commands.py +10 -6
- snowflake/cli/{plugins → _plugins}/init/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/nativeapp/artifacts.py +14 -0
- snowflake/cli/_plugins/nativeapp/bundle_context.py +31 -0
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/artifact_processor.py +3 -3
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/compiler.py +16 -18
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/setup/native_app_setup_processor.py +24 -28
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/extension_function_utils.py +4 -4
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/python_processor.py +20 -24
- snowflake/cli/{plugins → _plugins}/nativeapp/commands.py +171 -42
- snowflake/cli/{plugins → _plugins}/nativeapp/common_flags.py +1 -1
- snowflake/cli/{plugins → _plugins}/nativeapp/init.py +1 -1
- snowflake/cli/_plugins/nativeapp/manager.py +601 -0
- snowflake/cli/{plugins/connection → _plugins/nativeapp}/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/nativeapp/project_model.py +34 -11
- snowflake/cli/{plugins → _plugins}/nativeapp/run_processor.py +25 -23
- snowflake/cli/{plugins → _plugins}/nativeapp/teardown_processor.py +8 -8
- snowflake/cli/{plugins → _plugins}/nativeapp/v2_conversions/v2_to_v1_decorator.py +47 -28
- snowflake/cli/{plugins → _plugins}/nativeapp/version/commands.py +15 -12
- snowflake/cli/{plugins → _plugins}/nativeapp/version/version_processor.py +22 -20
- snowflake/cli/{plugins → _plugins}/notebook/commands.py +8 -6
- snowflake/cli/{plugins → _plugins}/notebook/manager.py +14 -14
- snowflake/cli/{plugins → _plugins}/notebook/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/notebook/types.py +0 -1
- snowflake/cli/{plugins → _plugins}/object/command_aliases.py +6 -5
- snowflake/cli/{plugins → _plugins}/object/commands.py +16 -10
- snowflake/cli/{plugins → _plugins}/object/manager.py +7 -6
- snowflake/cli/{plugins → _plugins}/object/plugin_spec.py +1 -1
- snowflake/cli/_plugins/snowpark/commands.py +510 -0
- snowflake/cli/_plugins/snowpark/common.py +252 -0
- snowflake/cli/{plugins → _plugins}/snowpark/models.py +0 -7
- snowflake/cli/{plugins → _plugins}/snowpark/package/anaconda_packages.py +1 -1
- snowflake/cli/{plugins → _plugins}/snowpark/package/commands.py +13 -74
- snowflake/cli/{plugins → _plugins}/snowpark/package/manager.py +4 -3
- snowflake/cli/{plugins → _plugins}/snowpark/package_utils.py +5 -5
- snowflake/cli/{plugins/nativeapp → _plugins/snowpark}/plugin_spec.py +1 -1
- snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +109 -0
- snowflake/cli/{plugins → _plugins}/snowpark/snowpark_shared.py +0 -36
- snowflake/cli/{plugins → _plugins}/snowpark/zipper.py +16 -8
- snowflake/cli/{plugins → _plugins}/spcs/__init__.py +5 -7
- snowflake/cli/{plugins → _plugins}/spcs/compute_pool/commands.py +29 -28
- snowflake/cli/{plugins → _plugins}/spcs/compute_pool/manager.py +3 -3
- snowflake/cli/{plugins → _plugins}/spcs/image_registry/commands.py +3 -3
- snowflake/cli/{plugins → _plugins}/spcs/image_repository/commands.py +25 -19
- snowflake/cli/{plugins → _plugins}/spcs/image_repository/manager.py +1 -1
- snowflake/cli/{plugins → _plugins}/spcs/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/spcs/services/commands.py +66 -32
- snowflake/cli/{plugins → _plugins}/spcs/services/manager.py +43 -5
- snowflake/cli/{plugins → _plugins}/sql/commands.py +19 -15
- snowflake/cli/{plugins → _plugins}/sql/manager.py +1 -1
- snowflake/cli/{plugins → _plugins}/sql/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/stage/commands.py +20 -17
- snowflake/cli/{plugins → _plugins}/stage/diff.py +1 -47
- snowflake/cli/{plugins → _plugins}/stage/manager.py +8 -6
- snowflake/cli/{plugins → _plugins}/stage/plugin_spec.py +1 -1
- snowflake/cli/_plugins/stage/utils.py +54 -0
- snowflake/cli/_plugins/streamlit/commands.py +242 -0
- snowflake/cli/{plugins → _plugins}/streamlit/manager.py +47 -70
- snowflake/cli/_plugins/streamlit/plugin_spec.py +30 -0
- snowflake/cli/_plugins/workspace/action_context.py +11 -0
- snowflake/cli/_plugins/workspace/commands.py +113 -0
- snowflake/cli/_plugins/workspace/manager.py +57 -0
- snowflake/cli/{plugins → _plugins}/workspace/plugin_spec.py +1 -1
- snowflake/cli/api/cli_global_context.py +34 -7
- snowflake/cli/api/commands/common.py +25 -0
- snowflake/cli/api/commands/decorators.py +4 -3
- snowflake/cli/api/commands/experimental_behaviour.py +2 -3
- snowflake/cli/api/commands/flags.py +73 -174
- snowflake/cli/api/commands/overrideable_parameter.py +143 -0
- snowflake/cli/api/commands/snow_typer.py +5 -4
- snowflake/cli/api/commands/typer_pre_execute.py +3 -3
- snowflake/cli/api/commands/utils.py +18 -0
- snowflake/cli/api/config.py +1 -1
- snowflake/cli/api/console/abc.py +5 -2
- snowflake/cli/api/entities/application_entity.py +12 -0
- snowflake/cli/api/entities/application_package_entity.py +260 -0
- snowflake/cli/api/entities/common.py +47 -0
- snowflake/cli/api/entities/snowpark_entity.py +29 -0
- snowflake/cli/api/entities/streamlit_entity.py +12 -0
- snowflake/cli/api/entities/utils.py +321 -0
- snowflake/cli/api/exceptions.py +19 -3
- snowflake/cli/api/feature_flags.py +2 -1
- snowflake/cli/api/identifiers.py +41 -9
- snowflake/cli/api/project/definition.py +13 -5
- snowflake/cli/api/project/definition_manager.py +12 -1
- snowflake/cli/api/project/errors.py +16 -1
- snowflake/cli/api/project/project_verification.py +3 -3
- snowflake/cli/api/project/schemas/entities/{application_entity.py → application_entity_model.py} +21 -9
- snowflake/cli/api/project/schemas/entities/{application_package_entity.py → application_package_entity_model.py} +26 -15
- snowflake/cli/api/project/schemas/entities/common.py +80 -6
- snowflake/cli/api/project/schemas/entities/entities.py +38 -8
- snowflake/cli/api/project/schemas/entities/snowpark_entity.py +176 -0
- snowflake/cli/api/project/schemas/entities/streamlit_entity_model.py +73 -0
- snowflake/cli/api/project/schemas/identifier_model.py +10 -1
- snowflake/cli/api/project/schemas/native_app/application.py +8 -9
- snowflake/cli/api/project/schemas/native_app/package.py +7 -1
- snowflake/cli/api/project/schemas/project_definition.py +97 -23
- snowflake/cli/api/project/schemas/updatable_model.py +11 -3
- snowflake/cli/api/project/util.py +23 -6
- snowflake/cli/api/rendering/jinja.py +28 -8
- snowflake/cli/api/rendering/sql_templates.py +41 -12
- snowflake/cli/api/secure_path.py +3 -0
- snowflake/cli/api/sql_execution.py +35 -19
- snowflake/cli/api/utils/definition_rendering.py +14 -2
- {snowflake_cli_labs-2.8.0rc0.dist-info → snowflake_cli_labs-3.0.0rc0.dist-info}/METADATA +12 -12
- snowflake_cli_labs-3.0.0rc0.dist-info/RECORD +234 -0
- snowflake_cli_labs-3.0.0rc0.dist-info/entry_points.txt +2 -0
- snowflake/cli/api/commands/project_initialisation.py +0 -65
- snowflake/cli/app/build_and_push.sh +0 -8
- snowflake/cli/plugins/nativeapp/manager.py +0 -819
- snowflake/cli/plugins/object_stage_deprecated/__init__.py +0 -15
- snowflake/cli/plugins/object_stage_deprecated/commands.py +0 -122
- snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +0 -32
- snowflake/cli/plugins/snowpark/commands.py +0 -548
- snowflake/cli/plugins/snowpark/common.py +0 -307
- snowflake/cli/plugins/snowpark/manager.py +0 -109
- snowflake/cli/plugins/snowpark/plugin_spec.py +0 -30
- snowflake/cli/plugins/snowpark/snowpark_package_paths.py +0 -65
- snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
- snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
- snowflake/cli/plugins/streamlit/commands.py +0 -186
- snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
- snowflake/cli/plugins/workspace/commands.py +0 -35
- snowflake/cli/templates/default_snowpark/.gitignore +0 -4
- snowflake/cli/templates/default_snowpark/app/__init__.py +0 -0
- snowflake/cli/templates/default_snowpark/app/common.py +0 -2
- snowflake/cli/templates/default_snowpark/app/functions.py +0 -15
- snowflake/cli/templates/default_snowpark/app/procedures.py +0 -22
- snowflake/cli/templates/default_snowpark/requirements.txt +0 -1
- snowflake/cli/templates/default_snowpark/snowflake.yml +0 -23
- snowflake/cli/templates/default_streamlit/.gitignore +0 -4
- snowflake/cli/templates/default_streamlit/common/hello.py +0 -2
- snowflake/cli/templates/default_streamlit/environment.yml +0 -6
- snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -3
- snowflake/cli/templates/default_streamlit/snowflake.yml +0 -10
- snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -4
- snowflake_cli_labs-2.8.0rc0.dist-info/RECORD +0 -240
- snowflake_cli_labs-2.8.0rc0.dist-info/entry_points.txt +0 -2
- /snowflake/cli/{app → _app}/__init__.py +0 -0
- /snowflake/cli/{app → _app}/api_impl/__init__.py +0 -0
- /snowflake/cli/{app → _app}/api_impl/plugin/__init__.py +0 -0
- /snowflake/cli/{app → _app}/api_impl/plugin/plugin_config_provider_impl.py +0 -0
- /snowflake/cli/{app → _app}/commands_registration/__init__.py +0 -0
- /snowflake/cli/{app → _app}/commands_registration/threadsafe.py +0 -0
- /snowflake/cli/{app → _app}/constants.py +0 -0
- /snowflake/cli/{app → _app}/dev/__init__.py +0 -0
- /snowflake/cli/{app → _app}/dev/commands_structure.py +0 -0
- /snowflake/cli/{app → _app}/dev/docs/__init__.py +0 -0
- /snowflake/cli/{app → _app}/dev/docs/project_definition_generate_json_schema.py +0 -0
- /snowflake/cli/{app → _app}/dev/docs/template_utils.py +0 -0
- /snowflake/cli/{app → _app}/dev/docs/templates/definition_description.rst.jinja2 +0 -0
- /snowflake/cli/{app → _app}/dev/docs/templates/overview.rst.jinja2 +0 -0
- /snowflake/cli/{app → _app}/dev/pycharm_remote_debug.py +0 -0
- /snowflake/cli/{app → _app}/loggers.py +0 -0
- /snowflake/cli/{plugins → _plugins}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/connection/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/cortex/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/cortex/types.py +0 -0
- /snowflake/cli/{plugins → _plugins}/git/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/init/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/sandbox.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/setup/setup_driver.py.source +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/models.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/constants.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/exceptions.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/feature_flags.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/policy.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/utils.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/version/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/notebook/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/notebook/exceptions.py +0 -0
- /snowflake/cli/{plugins → _plugins}/object/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/object/common.py +0 -0
- /snowflake/cli/{plugins → _plugins}/snowpark/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/snowpark/package/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/snowpark/package/utils.py +0 -0
- /snowflake/cli/{plugins → _plugins}/spcs/common.py +0 -0
- /snowflake/cli/{plugins → _plugins}/spcs/compute_pool/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/spcs/image_registry/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/spcs/image_registry/manager.py +0 -0
- /snowflake/cli/{plugins → _plugins}/spcs/image_repository/__init__.py +0 -0
- /snowflake/cli/{plugins/spcs/jobs → _plugins/spcs/services}/__init__.py +0 -0
- /snowflake/cli/{plugins/spcs/services → _plugins/sql}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/sql/snowsql_templating.py +0 -0
- /snowflake/cli/{plugins/sql → _plugins/stage}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/stage/md5.py +0 -0
- /snowflake/cli/{plugins/stage → _plugins/streamlit}/__init__.py +0 -0
- /snowflake/cli/{plugins/streamlit → _plugins/workspace}/__init__.py +0 -0
- /snowflake/cli/{plugins/workspace → api/project/schemas/entities}/__init__.py +0 -0
- {snowflake_cli_labs-2.8.0rc0.dist-info → snowflake_cli_labs-3.0.0rc0.dist-info}/WHEEL +0 -0
- {snowflake_cli_labs-2.8.0rc0.dist-info → snowflake_cli_labs-3.0.0rc0.dist-info}/licenses/LICENSE +0 -0
|
@@ -15,19 +15,21 @@
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
import tempfile
|
|
18
|
-
from dataclasses import dataclass
|
|
19
|
-
from enum import Enum
|
|
20
|
-
from inspect import signature
|
|
21
18
|
from pathlib import Path
|
|
22
|
-
from typing import Any, Callable,
|
|
19
|
+
from typing import Any, Callable, Optional
|
|
23
20
|
|
|
24
21
|
import click
|
|
25
22
|
import typer
|
|
26
23
|
from click import ClickException
|
|
27
|
-
from snowflake.cli.api.cli_global_context import
|
|
24
|
+
from snowflake.cli.api.cli_global_context import get_cli_context_manager
|
|
25
|
+
from snowflake.cli.api.commands.common import OnErrorType
|
|
26
|
+
from snowflake.cli.api.commands.overrideable_parameter import OverrideableOption
|
|
28
27
|
from snowflake.cli.api.commands.typer_pre_execute import register_pre_execute_command
|
|
28
|
+
from snowflake.cli.api.commands.utils import parse_key_value_variables
|
|
29
|
+
from snowflake.cli.api.config import get_all_connections
|
|
29
30
|
from snowflake.cli.api.console import cli_console
|
|
30
31
|
from snowflake.cli.api.exceptions import MissingConfiguration
|
|
32
|
+
from snowflake.cli.api.identifiers import FQN
|
|
31
33
|
from snowflake.cli.api.output.formats import OutputFormat
|
|
32
34
|
from snowflake.cli.api.project.definition_manager import DefinitionManager
|
|
33
35
|
from snowflake.cli.api.rendering.jinja import CONTEXT_KEY
|
|
@@ -38,111 +40,6 @@ _CONNECTION_SECTION = "Connection configuration"
|
|
|
38
40
|
_CLI_BEHAVIOUR = "Global configuration"
|
|
39
41
|
|
|
40
42
|
|
|
41
|
-
class OnErrorType(Enum):
|
|
42
|
-
BREAK = "break"
|
|
43
|
-
CONTINUE = "continue"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class OverrideableOption:
|
|
47
|
-
"""
|
|
48
|
-
Class that allows you to generate instances of typer.models.OptionInfo with some default properties while allowing
|
|
49
|
-
specific values to be overridden.
|
|
50
|
-
|
|
51
|
-
Custom parameters:
|
|
52
|
-
- mutually_exclusive (Tuple[str]|List[str]): A list of parameter names that this Option is not compatible with. If this Option has
|
|
53
|
-
a truthy value and any of the other parameters in the mutually_exclusive list has a truthy value, a
|
|
54
|
-
ClickException will be thrown. Note that mutually_exclusive can contain an option's own name but does not require
|
|
55
|
-
it.
|
|
56
|
-
"""
|
|
57
|
-
|
|
58
|
-
def __init__(
|
|
59
|
-
self,
|
|
60
|
-
default: Any,
|
|
61
|
-
*param_decls: str,
|
|
62
|
-
mutually_exclusive: Optional[List[str] | Tuple[str]] = None,
|
|
63
|
-
**kwargs,
|
|
64
|
-
):
|
|
65
|
-
self.default = default
|
|
66
|
-
self.param_decls = param_decls
|
|
67
|
-
self.mutually_exclusive = mutually_exclusive
|
|
68
|
-
self.kwargs = kwargs
|
|
69
|
-
|
|
70
|
-
def __call__(self, **kwargs) -> typer.models.OptionInfo:
|
|
71
|
-
"""
|
|
72
|
-
Returns a typer.models.OptionInfo instance initialized with the specified default values along with any overrides
|
|
73
|
-
from kwargs. Note that if you are overriding param_decls, you must pass an iterable of strings, you cannot use
|
|
74
|
-
positional arguments like you can with typer.Option. Does not modify the original instance.
|
|
75
|
-
"""
|
|
76
|
-
default = kwargs.get("default", self.default)
|
|
77
|
-
param_decls = kwargs.get("param_decls", self.param_decls)
|
|
78
|
-
mutually_exclusive = kwargs.get("mutually_exclusive", self.mutually_exclusive)
|
|
79
|
-
if not isinstance(param_decls, list) and not isinstance(param_decls, tuple):
|
|
80
|
-
raise TypeError("param_decls must be a list or tuple")
|
|
81
|
-
passed_kwargs = self.kwargs.copy()
|
|
82
|
-
passed_kwargs.update(kwargs)
|
|
83
|
-
if passed_kwargs.get("callback", None) or mutually_exclusive:
|
|
84
|
-
passed_kwargs["callback"] = self._callback_factory(
|
|
85
|
-
passed_kwargs.get("callback", None), mutually_exclusive
|
|
86
|
-
)
|
|
87
|
-
for non_kwarg in ["default", "param_decls", "mutually_exclusive"]:
|
|
88
|
-
passed_kwargs.pop(non_kwarg, None)
|
|
89
|
-
return typer.Option(default, *param_decls, **passed_kwargs)
|
|
90
|
-
|
|
91
|
-
class InvalidCallbackSignature(ClickException):
|
|
92
|
-
def __init__(self, callback):
|
|
93
|
-
super().__init__(
|
|
94
|
-
f"Signature {signature(callback)} is not valid for an OverrideableOption callback function. Must have at most one parameter with each of the following types: (typer.Context, typer.CallbackParam, Any Other Type)"
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
def _callback_factory(
|
|
98
|
-
self, callback, mutually_exclusive: Optional[List[str] | Tuple[str]]
|
|
99
|
-
):
|
|
100
|
-
callback = callback if callback else lambda x: x
|
|
101
|
-
|
|
102
|
-
# inspect existing_callback to make sure signature is valid
|
|
103
|
-
existing_params = signature(callback).parameters
|
|
104
|
-
# at most one parameter with each type in [typer.Context, typer.CallbackParam, any other type]
|
|
105
|
-
limits = [
|
|
106
|
-
lambda x: x == typer.Context,
|
|
107
|
-
lambda x: x == typer.CallbackParam,
|
|
108
|
-
lambda x: x != typer.Context and x != typer.CallbackParam,
|
|
109
|
-
]
|
|
110
|
-
for limit in limits:
|
|
111
|
-
if len([v for v in existing_params.values() if limit(v.annotation)]) > 1:
|
|
112
|
-
raise self.InvalidCallbackSignature(callback)
|
|
113
|
-
|
|
114
|
-
def generated_callback(ctx: typer.Context, param: typer.CallbackParam, value):
|
|
115
|
-
if mutually_exclusive:
|
|
116
|
-
for name in mutually_exclusive:
|
|
117
|
-
if value and ctx.params.get(
|
|
118
|
-
name, False
|
|
119
|
-
): # if the current parameter is set to True and a previous parameter is also Truthy
|
|
120
|
-
curr_opt = param.opts[0]
|
|
121
|
-
other_opt = [x for x in ctx.command.params if x.name == name][
|
|
122
|
-
0
|
|
123
|
-
].opts[0]
|
|
124
|
-
raise click.ClickException(
|
|
125
|
-
f"Options '{curr_opt}' and '{other_opt}' are incompatible."
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
# pass args to existing callback based on its signature (this is how Typer infers callback args)
|
|
129
|
-
passed_params = {}
|
|
130
|
-
for existing_param in existing_params:
|
|
131
|
-
annotation = existing_params[existing_param].annotation
|
|
132
|
-
if annotation == typer.Context:
|
|
133
|
-
passed_params[existing_param] = ctx
|
|
134
|
-
elif annotation == typer.CallbackParam:
|
|
135
|
-
passed_params[existing_param] = param
|
|
136
|
-
else:
|
|
137
|
-
passed_params[existing_param] = value
|
|
138
|
-
return callback(**passed_params)
|
|
139
|
-
|
|
140
|
-
return generated_callback
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
from snowflake.cli.api.config import get_all_connections
|
|
144
|
-
|
|
145
|
-
|
|
146
43
|
def _callback(provide_setter: Callable[[], Callable[[Any], Any]]):
|
|
147
44
|
def callback(value):
|
|
148
45
|
set_value = provide_setter()
|
|
@@ -159,11 +56,11 @@ ConnectionOption = typer.Option(
|
|
|
159
56
|
"--environment",
|
|
160
57
|
help=f"Name of the connection, as defined in your `config.toml`. Default: `default`.",
|
|
161
58
|
callback=_callback(
|
|
162
|
-
lambda:
|
|
59
|
+
lambda: get_cli_context_manager().connection_context.set_connection_name
|
|
163
60
|
),
|
|
164
61
|
show_default=False,
|
|
165
62
|
rich_help_panel=_CONNECTION_SECTION,
|
|
166
|
-
|
|
63
|
+
shell_complete=lambda _, __, ___: list(get_all_connections()),
|
|
167
64
|
)
|
|
168
65
|
|
|
169
66
|
TemporaryConnectionOption = typer.Option(
|
|
@@ -172,7 +69,7 @@ TemporaryConnectionOption = typer.Option(
|
|
|
172
69
|
"-x",
|
|
173
70
|
help="Uses connection defined with command line parameters, instead of one defined in config",
|
|
174
71
|
callback=_callback(
|
|
175
|
-
lambda:
|
|
72
|
+
lambda: get_cli_context_manager().connection_context.set_temporary_connection
|
|
176
73
|
),
|
|
177
74
|
is_flag=True,
|
|
178
75
|
rich_help_panel=_CONNECTION_SECTION,
|
|
@@ -183,7 +80,9 @@ AccountOption = typer.Option(
|
|
|
183
80
|
"--account",
|
|
184
81
|
"--accountname",
|
|
185
82
|
help="Name assigned to your Snowflake account. Overrides the value specified for the connection.",
|
|
186
|
-
callback=_callback(
|
|
83
|
+
callback=_callback(
|
|
84
|
+
lambda: get_cli_context_manager().connection_context.set_account
|
|
85
|
+
),
|
|
187
86
|
show_default=False,
|
|
188
87
|
rich_help_panel=_CONNECTION_SECTION,
|
|
189
88
|
)
|
|
@@ -193,7 +92,7 @@ UserOption = typer.Option(
|
|
|
193
92
|
"--user",
|
|
194
93
|
"--username",
|
|
195
94
|
help="Username to connect to Snowflake. Overrides the value specified for the connection.",
|
|
196
|
-
callback=_callback(lambda:
|
|
95
|
+
callback=_callback(lambda: get_cli_context_manager().connection_context.set_user),
|
|
197
96
|
show_default=False,
|
|
198
97
|
rich_help_panel=_CONNECTION_SECTION,
|
|
199
98
|
)
|
|
@@ -206,7 +105,9 @@ def _password_callback(value: str):
|
|
|
206
105
|
if value:
|
|
207
106
|
cli_console.message(PLAIN_PASSWORD_MSG)
|
|
208
107
|
|
|
209
|
-
return _callback(lambda:
|
|
108
|
+
return _callback(lambda: get_cli_context_manager().connection_context.set_password)(
|
|
109
|
+
value
|
|
110
|
+
)
|
|
210
111
|
|
|
211
112
|
|
|
212
113
|
PasswordOption = typer.Option(
|
|
@@ -225,7 +126,7 @@ AuthenticatorOption = typer.Option(
|
|
|
225
126
|
help="Snowflake authenticator. Overrides the value specified for the connection.",
|
|
226
127
|
hide_input=True,
|
|
227
128
|
callback=_callback(
|
|
228
|
-
lambda:
|
|
129
|
+
lambda: get_cli_context_manager().connection_context.set_authenticator
|
|
229
130
|
),
|
|
230
131
|
show_default=False,
|
|
231
132
|
rich_help_panel=_CONNECTION_SECTION,
|
|
@@ -237,7 +138,7 @@ PrivateKeyPathOption = typer.Option(
|
|
|
237
138
|
help="Snowflake private key path. Overrides the value specified for the connection.",
|
|
238
139
|
hide_input=True,
|
|
239
140
|
callback=_callback(
|
|
240
|
-
lambda:
|
|
141
|
+
lambda: get_cli_context_manager().connection_context.set_private_key_path
|
|
241
142
|
),
|
|
242
143
|
show_default=False,
|
|
243
144
|
rich_help_panel=_CONNECTION_SECTION,
|
|
@@ -252,7 +153,7 @@ SessionTokenOption = typer.Option(
|
|
|
252
153
|
help="Snowflake session token. Can be used only in conjunction with --master-token. Overrides the value specified for the connection.",
|
|
253
154
|
hide_input=True,
|
|
254
155
|
callback=_callback(
|
|
255
|
-
lambda:
|
|
156
|
+
lambda: get_cli_context_manager().connection_context.set_session_token
|
|
256
157
|
),
|
|
257
158
|
show_default=False,
|
|
258
159
|
rich_help_panel=_CONNECTION_SECTION,
|
|
@@ -267,7 +168,9 @@ MasterTokenOption = typer.Option(
|
|
|
267
168
|
"--master-token",
|
|
268
169
|
help="Snowflake master token. Can be used only in conjunction with --session-token. Overrides the value specified for the connection.",
|
|
269
170
|
hide_input=True,
|
|
270
|
-
callback=_callback(
|
|
171
|
+
callback=_callback(
|
|
172
|
+
lambda: get_cli_context_manager().connection_context.set_master_token
|
|
173
|
+
),
|
|
271
174
|
show_default=False,
|
|
272
175
|
rich_help_panel=_CONNECTION_SECTION,
|
|
273
176
|
exists=True,
|
|
@@ -281,7 +184,7 @@ TokenFilePathOption = typer.Option(
|
|
|
281
184
|
"--token-file-path",
|
|
282
185
|
help="Path to file with an OAuth token that should be used when connecting to Snowflake",
|
|
283
186
|
callback=_callback(
|
|
284
|
-
lambda:
|
|
187
|
+
lambda: get_cli_context_manager().connection_context.set_token_file_path
|
|
285
188
|
),
|
|
286
189
|
show_default=False,
|
|
287
190
|
rich_help_panel=_CONNECTION_SECTION,
|
|
@@ -295,7 +198,9 @@ DatabaseOption = typer.Option(
|
|
|
295
198
|
"--database",
|
|
296
199
|
"--dbname",
|
|
297
200
|
help="Database to use. Overrides the value specified for the connection.",
|
|
298
|
-
callback=_callback(
|
|
201
|
+
callback=_callback(
|
|
202
|
+
lambda: get_cli_context_manager().connection_context.set_database
|
|
203
|
+
),
|
|
299
204
|
show_default=False,
|
|
300
205
|
rich_help_panel=_CONNECTION_SECTION,
|
|
301
206
|
)
|
|
@@ -305,7 +210,7 @@ SchemaOption = typer.Option(
|
|
|
305
210
|
"--schema",
|
|
306
211
|
"--schemaname",
|
|
307
212
|
help="Database schema to use. Overrides the value specified for the connection.",
|
|
308
|
-
callback=_callback(lambda:
|
|
213
|
+
callback=_callback(lambda: get_cli_context_manager().connection_context.set_schema),
|
|
309
214
|
show_default=False,
|
|
310
215
|
rich_help_panel=_CONNECTION_SECTION,
|
|
311
216
|
)
|
|
@@ -315,7 +220,7 @@ RoleOption = typer.Option(
|
|
|
315
220
|
"--role",
|
|
316
221
|
"--rolename",
|
|
317
222
|
help="Role to use. Overrides the value specified for the connection.",
|
|
318
|
-
callback=_callback(lambda:
|
|
223
|
+
callback=_callback(lambda: get_cli_context_manager().connection_context.set_role),
|
|
319
224
|
show_default=False,
|
|
320
225
|
rich_help_panel=_CONNECTION_SECTION,
|
|
321
226
|
)
|
|
@@ -324,7 +229,9 @@ WarehouseOption = typer.Option(
|
|
|
324
229
|
None,
|
|
325
230
|
"--warehouse",
|
|
326
231
|
help="Warehouse to use. Overrides the value specified for the connection.",
|
|
327
|
-
callback=_callback(
|
|
232
|
+
callback=_callback(
|
|
233
|
+
lambda: get_cli_context_manager().connection_context.set_warehouse
|
|
234
|
+
),
|
|
328
235
|
show_default=False,
|
|
329
236
|
rich_help_panel=_CONNECTION_SECTION,
|
|
330
237
|
)
|
|
@@ -333,7 +240,9 @@ MfaPasscodeOption = typer.Option(
|
|
|
333
240
|
None,
|
|
334
241
|
"--mfa-passcode",
|
|
335
242
|
help="Token to use for multi-factor authentication (MFA)",
|
|
336
|
-
callback=_callback(
|
|
243
|
+
callback=_callback(
|
|
244
|
+
lambda: get_cli_context_manager().connection_context.set_mfa_passcode
|
|
245
|
+
),
|
|
337
246
|
prompt="MFA passcode",
|
|
338
247
|
prompt_required=False,
|
|
339
248
|
show_default=False,
|
|
@@ -344,18 +253,31 @@ EnableDiagOption = typer.Option(
|
|
|
344
253
|
False,
|
|
345
254
|
"--enable-diag",
|
|
346
255
|
help="Run python connector diagnostic test",
|
|
347
|
-
callback=_callback(
|
|
256
|
+
callback=_callback(
|
|
257
|
+
lambda: get_cli_context_manager().connection_context.set_enable_diag
|
|
258
|
+
),
|
|
348
259
|
show_default=False,
|
|
349
260
|
is_flag=True,
|
|
350
261
|
rich_help_panel=_CONNECTION_SECTION,
|
|
351
262
|
)
|
|
352
263
|
|
|
264
|
+
# Set default via callback to avoid including tempdir path in generated docs (snow --docs).
|
|
265
|
+
# Use constant instead of None, as None is removed from telemetry data.
|
|
266
|
+
_DIAG_LOG_DEFAULT_VALUE = "<temporary_directory>"
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def _diag_log_path_callback(path: str):
|
|
270
|
+
if path != _DIAG_LOG_DEFAULT_VALUE:
|
|
271
|
+
return path
|
|
272
|
+
return tempfile.gettempdir()
|
|
273
|
+
|
|
274
|
+
|
|
353
275
|
DiagLogPathOption: Path = typer.Option(
|
|
354
|
-
|
|
276
|
+
_DIAG_LOG_DEFAULT_VALUE,
|
|
355
277
|
"--diag-log-path",
|
|
356
278
|
help="Diagnostic report path",
|
|
357
279
|
callback=_callback(
|
|
358
|
-
lambda:
|
|
280
|
+
lambda: get_cli_context_manager().connection_context.set_diag_log_path
|
|
359
281
|
),
|
|
360
282
|
show_default=False,
|
|
361
283
|
rich_help_panel=_CONNECTION_SECTION,
|
|
@@ -368,7 +290,7 @@ DiagAllowlistPathOption: Path = typer.Option(
|
|
|
368
290
|
"--diag-allowlist-path",
|
|
369
291
|
help="Diagnostic report path to optional allowlist",
|
|
370
292
|
callback=_callback(
|
|
371
|
-
lambda:
|
|
293
|
+
lambda: get_cli_context_manager().connection_context.set_diag_allowlist_path
|
|
372
294
|
),
|
|
373
295
|
show_default=False,
|
|
374
296
|
rich_help_panel=_CONNECTION_SECTION,
|
|
@@ -381,7 +303,7 @@ OutputFormatOption = typer.Option(
|
|
|
381
303
|
"--format",
|
|
382
304
|
help="Specifies the output format.",
|
|
383
305
|
case_sensitive=False,
|
|
384
|
-
callback=_callback(lambda:
|
|
306
|
+
callback=_callback(lambda: get_cli_context_manager().set_output_format),
|
|
385
307
|
rich_help_panel=_CLI_BEHAVIOUR,
|
|
386
308
|
)
|
|
387
309
|
|
|
@@ -389,7 +311,7 @@ SilentOption = typer.Option(
|
|
|
389
311
|
False,
|
|
390
312
|
"--silent",
|
|
391
313
|
help="Turns off intermediate output to console.",
|
|
392
|
-
callback=_callback(lambda:
|
|
314
|
+
callback=_callback(lambda: get_cli_context_manager().set_silent),
|
|
393
315
|
is_flag=True,
|
|
394
316
|
rich_help_panel=_CLI_BEHAVIOUR,
|
|
395
317
|
is_eager=True,
|
|
@@ -400,7 +322,7 @@ VerboseOption = typer.Option(
|
|
|
400
322
|
"--verbose",
|
|
401
323
|
"-v",
|
|
402
324
|
help="Displays log entries for log levels `info` and higher.",
|
|
403
|
-
callback=_callback(lambda:
|
|
325
|
+
callback=_callback(lambda: get_cli_context_manager().set_verbose),
|
|
404
326
|
is_flag=True,
|
|
405
327
|
rich_help_panel=_CLI_BEHAVIOUR,
|
|
406
328
|
)
|
|
@@ -409,7 +331,7 @@ DebugOption = typer.Option(
|
|
|
409
331
|
False,
|
|
410
332
|
"--debug",
|
|
411
333
|
help="Displays log entries for log levels `debug` and higher; debug logs contains additional information.",
|
|
412
|
-
callback=_callback(lambda:
|
|
334
|
+
callback=_callback(lambda: get_cli_context_manager().set_enable_tracebacks),
|
|
413
335
|
is_flag=True,
|
|
414
336
|
rich_help_panel=_CLI_BEHAVIOUR,
|
|
415
337
|
)
|
|
@@ -450,6 +372,10 @@ OnErrorOption = typer.Option(
|
|
|
450
372
|
NoInteractiveOption = typer.Option(False, "--no-interactive", help="Disable prompting.")
|
|
451
373
|
|
|
452
374
|
|
|
375
|
+
def entity_argument(entity_type: str) -> typer.Argument:
|
|
376
|
+
return typer.Argument(None, help=f"ID of {entity_type} entity.")
|
|
377
|
+
|
|
378
|
+
|
|
453
379
|
def variables_option(description: str):
|
|
454
380
|
return typer.Option(
|
|
455
381
|
None,
|
|
@@ -508,17 +434,21 @@ def experimental_option(
|
|
|
508
434
|
"--experimental",
|
|
509
435
|
help=help_text,
|
|
510
436
|
hidden=True,
|
|
511
|
-
callback=_callback(lambda:
|
|
437
|
+
callback=_callback(lambda: get_cli_context_manager().set_experimental),
|
|
512
438
|
is_flag=True,
|
|
513
439
|
rich_help_panel=_CLI_BEHAVIOUR,
|
|
514
440
|
)
|
|
515
441
|
|
|
516
442
|
|
|
517
|
-
def identifier_argument(
|
|
443
|
+
def identifier_argument(
|
|
444
|
+
sf_object: str, example: str, callback: Callable | None = None
|
|
445
|
+
) -> typer.Argument:
|
|
518
446
|
return typer.Argument(
|
|
519
447
|
...,
|
|
520
448
|
help=f"Identifier of the {sf_object}. For example: {example}",
|
|
521
449
|
show_default=False,
|
|
450
|
+
click_type=IdentifierType(),
|
|
451
|
+
callback=callback,
|
|
522
452
|
)
|
|
523
453
|
|
|
524
454
|
|
|
@@ -531,6 +461,7 @@ def execution_identifier_argument(sf_object: str, example: str) -> typer.Argumen
|
|
|
531
461
|
|
|
532
462
|
|
|
533
463
|
def register_project_definition(is_optional: bool) -> None:
|
|
464
|
+
cli_context_manager = get_cli_context_manager()
|
|
534
465
|
project_path = cli_context_manager.project_path_arg
|
|
535
466
|
env_overrides_args = cli_context_manager.project_env_overrides_args
|
|
536
467
|
|
|
@@ -551,7 +482,7 @@ def register_project_definition(is_optional: bool) -> None:
|
|
|
551
482
|
|
|
552
483
|
def project_definition_option(is_optional: bool):
|
|
553
484
|
def project_definition_callback(project_path: str) -> None:
|
|
554
|
-
|
|
485
|
+
get_cli_context_manager().set_project_path_arg(project_path)
|
|
555
486
|
register_pre_execute_command(lambda: register_project_definition(is_optional))
|
|
556
487
|
|
|
557
488
|
return typer.Option(
|
|
@@ -570,7 +501,7 @@ def project_env_overrides_option():
|
|
|
570
501
|
env_overrides_args_map = {
|
|
571
502
|
v.key: v.value for v in parse_key_value_variables(env_overrides_args_list)
|
|
572
503
|
}
|
|
573
|
-
|
|
504
|
+
get_cli_context_manager().set_project_env_overrides_args(env_overrides_args_map)
|
|
574
505
|
|
|
575
506
|
return typer.Option(
|
|
576
507
|
[],
|
|
@@ -581,19 +512,6 @@ def project_env_overrides_option():
|
|
|
581
512
|
)
|
|
582
513
|
|
|
583
514
|
|
|
584
|
-
def readable_file_option(param_name: str, help_str: str) -> typer.Option:
|
|
585
|
-
return typer.Option(
|
|
586
|
-
None,
|
|
587
|
-
param_name,
|
|
588
|
-
exists=True,
|
|
589
|
-
file_okay=True,
|
|
590
|
-
dir_okay=False,
|
|
591
|
-
readable=True,
|
|
592
|
-
help=help_str,
|
|
593
|
-
show_default=False,
|
|
594
|
-
)
|
|
595
|
-
|
|
596
|
-
|
|
597
515
|
def deprecated_flag_callback(msg: str):
|
|
598
516
|
def _warning_callback(ctx: click.Context, param: click.Parameter, value: Any):
|
|
599
517
|
if ctx.get_parameter_source(param.name) != click.core.ParameterSource.DEFAULT: # type: ignore[attr-defined]
|
|
@@ -614,27 +532,8 @@ def deprecated_flag_callback_enum(msg: str):
|
|
|
614
532
|
return _warning_callback
|
|
615
533
|
|
|
616
534
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
key: str
|
|
620
|
-
value: str
|
|
621
|
-
|
|
622
|
-
def __init__(self, key: str, value: str):
|
|
623
|
-
self.key = key
|
|
624
|
-
self.value = value
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
def parse_key_value_variables(variables: Optional[List[str]]) -> List[Variable]:
|
|
628
|
-
"""Util for parsing key=value input. Useful for commands accepting multiple input options."""
|
|
629
|
-
if not variables:
|
|
630
|
-
return []
|
|
631
|
-
result: List[Variable] = []
|
|
632
|
-
if not variables:
|
|
633
|
-
return result
|
|
634
|
-
for p in variables:
|
|
635
|
-
if "=" not in p:
|
|
636
|
-
raise ClickException(f"Invalid variable: '{p}'")
|
|
535
|
+
class IdentifierType(click.ParamType):
|
|
536
|
+
name = "TEXT"
|
|
637
537
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
return result
|
|
538
|
+
def convert(self, value, param, ctx):
|
|
539
|
+
return FQN.from_string(value)
|
|
@@ -0,0 +1,143 @@
|
|
|
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 abc import ABC, abstractmethod
|
|
18
|
+
from inspect import signature
|
|
19
|
+
from typing import Any, List, Optional, Tuple
|
|
20
|
+
|
|
21
|
+
import typer
|
|
22
|
+
from click import ClickException
|
|
23
|
+
from snowflake.cli.api.exceptions import IncompatibleParametersError
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class _OverrideableParameter(ABC):
|
|
27
|
+
"""
|
|
28
|
+
Class that allows you to generate instances of typer.models.OptionInfo with some default properties while allowing
|
|
29
|
+
specific values to be overridden.
|
|
30
|
+
|
|
31
|
+
Custom parameters:
|
|
32
|
+
- mutually_exclusive (Tuple[str]|List[str]): A list of parameter names that this Option is not compatible with. If this Option has
|
|
33
|
+
a truthy value and any of the other parameters in the mutually_exclusive list has a truthy value, a
|
|
34
|
+
ClickException will be thrown. Note that mutually_exclusive can contain an option's own name but does not require
|
|
35
|
+
it.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
default: Any = ...,
|
|
41
|
+
*param_decls: str,
|
|
42
|
+
mutually_exclusive: Optional[List[str] | Tuple[str]] = None,
|
|
43
|
+
**kwargs,
|
|
44
|
+
):
|
|
45
|
+
self.default = default
|
|
46
|
+
self.param_decls = param_decls
|
|
47
|
+
self.mutually_exclusive = mutually_exclusive
|
|
48
|
+
self.kwargs = kwargs
|
|
49
|
+
|
|
50
|
+
def __call__(self, **kwargs) -> typer.models.ParameterInfo:
|
|
51
|
+
"""
|
|
52
|
+
Returns a typer.models.OptionInfo instance initialized with the specified default values along with any overrides
|
|
53
|
+
from kwargs. Note that if you are overriding param_decls, you must pass an iterable of strings, you cannot use
|
|
54
|
+
positional arguments like you can with typer.Option. Does not modify the original instance.
|
|
55
|
+
"""
|
|
56
|
+
default = kwargs.get("default", self.default)
|
|
57
|
+
param_decls = kwargs.get("param_decls", self.param_decls)
|
|
58
|
+
mutually_exclusive = kwargs.get("mutually_exclusive", self.mutually_exclusive)
|
|
59
|
+
if not isinstance(param_decls, list) and not isinstance(param_decls, tuple):
|
|
60
|
+
raise TypeError("param_decls must be a list or tuple")
|
|
61
|
+
passed_kwargs = self.kwargs.copy()
|
|
62
|
+
passed_kwargs.update(kwargs)
|
|
63
|
+
if passed_kwargs.get("callback", None) or mutually_exclusive:
|
|
64
|
+
passed_kwargs["callback"] = self._callback_factory(
|
|
65
|
+
passed_kwargs.get("callback", None), mutually_exclusive
|
|
66
|
+
)
|
|
67
|
+
for non_kwarg in ["default", "param_decls", "mutually_exclusive"]:
|
|
68
|
+
passed_kwargs.pop(non_kwarg, None)
|
|
69
|
+
|
|
70
|
+
return self.get_parameter(default, *param_decls, **passed_kwargs)
|
|
71
|
+
|
|
72
|
+
@abstractmethod
|
|
73
|
+
def get_parameter(
|
|
74
|
+
self, default: Any = None, *param_decls: str, **kwargs
|
|
75
|
+
) -> typer.models.ParameterInfo:
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
class InvalidCallbackSignature(ClickException):
|
|
79
|
+
def __init__(self, callback):
|
|
80
|
+
super().__init__(
|
|
81
|
+
f"Signature {signature(callback)} is not valid for an OverrideableOption callback function. Must have "
|
|
82
|
+
f"at most one parameter with each of the following types: (typer.Context, typer.CallbackParam, "
|
|
83
|
+
f"Any Other Type)"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def _callback_factory(
|
|
87
|
+
self, callback, mutually_exclusive: Optional[List[str] | Tuple[str]]
|
|
88
|
+
):
|
|
89
|
+
callback = callback if callback else lambda x: x
|
|
90
|
+
|
|
91
|
+
# inspect existing_callback to make sure signature is valid
|
|
92
|
+
existing_params = signature(callback).parameters
|
|
93
|
+
# at most one parameter with each type in [typer.Context, typer.CallbackParam, any other type]
|
|
94
|
+
limits = [
|
|
95
|
+
lambda x: x == typer.Context,
|
|
96
|
+
lambda x: x == typer.CallbackParam,
|
|
97
|
+
lambda x: x != typer.Context and x != typer.CallbackParam,
|
|
98
|
+
]
|
|
99
|
+
for limit in limits:
|
|
100
|
+
if len([v for v in existing_params.values() if limit(v.annotation)]) > 1:
|
|
101
|
+
raise self.InvalidCallbackSignature(callback)
|
|
102
|
+
|
|
103
|
+
def generated_callback(ctx: typer.Context, param: typer.CallbackParam, value):
|
|
104
|
+
if mutually_exclusive:
|
|
105
|
+
for name in mutually_exclusive:
|
|
106
|
+
if value and ctx.params.get(
|
|
107
|
+
name, False
|
|
108
|
+
): # if the current parameter is set to True and a previous parameter is also Truthy
|
|
109
|
+
curr_opt = param.opts[0]
|
|
110
|
+
other_opt = [x for x in ctx.command.params if x.name == name][
|
|
111
|
+
0
|
|
112
|
+
].opts[0]
|
|
113
|
+
raise IncompatibleParametersError([curr_opt, other_opt])
|
|
114
|
+
|
|
115
|
+
# pass args to existing callback based on its signature (this is how Typer infers callback args)
|
|
116
|
+
passed_params = {}
|
|
117
|
+
for existing_param in existing_params:
|
|
118
|
+
annotation = existing_params[existing_param].annotation
|
|
119
|
+
if annotation == typer.Context:
|
|
120
|
+
passed_params[existing_param] = ctx
|
|
121
|
+
elif annotation == typer.CallbackParam:
|
|
122
|
+
passed_params[existing_param] = param
|
|
123
|
+
else:
|
|
124
|
+
passed_params[existing_param] = value
|
|
125
|
+
return callback(**passed_params)
|
|
126
|
+
|
|
127
|
+
return generated_callback
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class OverrideableArgument(_OverrideableParameter):
|
|
131
|
+
def get_parameter(
|
|
132
|
+
self, default: Any = ..., *param_decls: str, **kwargs
|
|
133
|
+
) -> typer.models.ArgumentInfo:
|
|
134
|
+
return typer.Argument(default, *param_decls, **kwargs)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
# OverrideableOption doesn't work with flags with type List[Any] and default None, because typer executes the callback
|
|
138
|
+
# function which converts the default value iterating over it, but None is not iterable.
|
|
139
|
+
class OverrideableOption(_OverrideableParameter):
|
|
140
|
+
def get_parameter(
|
|
141
|
+
self, default: Any = ..., *param_decls: str, **kwargs
|
|
142
|
+
) -> typer.models.OptionInfo:
|
|
143
|
+
return typer.Option(default, *param_decls, **kwargs)
|
|
@@ -46,6 +46,7 @@ class SnowTyper(typer.Typer):
|
|
|
46
46
|
pretty_exceptions_show_locals=False,
|
|
47
47
|
no_args_is_help=True,
|
|
48
48
|
add_completion=True,
|
|
49
|
+
rich_markup_mode="markdown",
|
|
49
50
|
)
|
|
50
51
|
|
|
51
52
|
@staticmethod
|
|
@@ -121,7 +122,7 @@ class SnowTyper(typer.Typer):
|
|
|
121
122
|
Pay attention to make this method safe to use if performed operations are not necessary
|
|
122
123
|
for executing the command in proper way.
|
|
123
124
|
"""
|
|
124
|
-
from snowflake.cli.
|
|
125
|
+
from snowflake.cli._app.telemetry import log_command_usage
|
|
125
126
|
|
|
126
127
|
log.debug("Executing command pre execution callback")
|
|
127
128
|
run_pre_execute_commands()
|
|
@@ -130,7 +131,7 @@ class SnowTyper(typer.Typer):
|
|
|
130
131
|
@staticmethod
|
|
131
132
|
def process_result(result):
|
|
132
133
|
"""Command result processor"""
|
|
133
|
-
from snowflake.cli.
|
|
134
|
+
from snowflake.cli._app.printing import print_result
|
|
134
135
|
|
|
135
136
|
# Because we still have commands like "logs" that do not return anything.
|
|
136
137
|
# We should improve it in future.
|
|
@@ -145,7 +146,7 @@ class SnowTyper(typer.Typer):
|
|
|
145
146
|
"""
|
|
146
147
|
Callback executed on command execution error.
|
|
147
148
|
"""
|
|
148
|
-
from snowflake.cli.
|
|
149
|
+
from snowflake.cli._app.telemetry import log_command_execution_error
|
|
149
150
|
|
|
150
151
|
log.debug("Executing command exception callback")
|
|
151
152
|
log_command_execution_error(exception, execution)
|
|
@@ -156,7 +157,7 @@ class SnowTyper(typer.Typer):
|
|
|
156
157
|
Callback executed after running any command callable. Pay attention to make this method safe to
|
|
157
158
|
use if performed operations are not necessary for executing the command in proper way.
|
|
158
159
|
"""
|
|
159
|
-
from snowflake.cli.
|
|
160
|
+
from snowflake.cli._app.telemetry import flush_telemetry, log_command_result
|
|
160
161
|
|
|
161
162
|
log.debug("Executing command post execution callback")
|
|
162
163
|
log_command_result(execution)
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
|
|
15
15
|
from typing import Callable
|
|
16
16
|
|
|
17
|
-
from snowflake.cli.api.cli_global_context import
|
|
17
|
+
from snowflake.cli.api.cli_global_context import get_cli_context_manager
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def register_pre_execute_command(command: Callable[[], None]) -> None:
|
|
21
|
-
|
|
21
|
+
get_cli_context_manager().add_typer_pre_execute_commands(command)
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def run_pre_execute_commands() -> None:
|
|
25
|
-
for command in
|
|
25
|
+
for command in get_cli_context_manager().typer_pre_execute_commands:
|
|
26
26
|
command()
|