snowflake-cli 2.8.2__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 +17 -0
- snowflake/cli/__init__.py +13 -0
- snowflake/cli/api/__init__.py +48 -0
- snowflake/cli/api/cli_global_context.py +390 -0
- snowflake/cli/api/commands/__init__.py +13 -0
- snowflake/cli/api/commands/alias.py +23 -0
- snowflake/cli/api/commands/decorators.py +354 -0
- snowflake/cli/api/commands/execution_metadata.py +40 -0
- snowflake/cli/api/commands/experimental_behaviour.py +19 -0
- snowflake/cli/api/commands/flags.py +662 -0
- snowflake/cli/api/commands/project_initialisation.py +65 -0
- snowflake/cli/api/commands/snow_typer.py +237 -0
- snowflake/cli/api/commands/typer_pre_execute.py +26 -0
- snowflake/cli/api/config.py +348 -0
- snowflake/cli/api/console/__init__.py +17 -0
- snowflake/cli/api/console/abc.py +89 -0
- snowflake/cli/api/console/console.py +134 -0
- snowflake/cli/api/console/enum.py +17 -0
- snowflake/cli/api/constants.py +79 -0
- snowflake/cli/api/errno.py +27 -0
- snowflake/cli/api/exceptions.py +164 -0
- snowflake/cli/api/feature_flags.py +55 -0
- snowflake/cli/api/identifiers.py +167 -0
- snowflake/cli/api/output/__init__.py +13 -0
- snowflake/cli/api/output/formats.py +20 -0
- snowflake/cli/api/output/types.py +118 -0
- snowflake/cli/api/plugins/__init__.py +13 -0
- snowflake/cli/api/plugins/command/__init__.py +72 -0
- snowflake/cli/api/plugins/command/plugin_hook_specs.py +21 -0
- snowflake/cli/api/plugins/plugin_config.py +32 -0
- snowflake/cli/api/project/__init__.py +13 -0
- snowflake/cli/api/project/definition.py +84 -0
- snowflake/cli/api/project/definition_manager.py +134 -0
- snowflake/cli/api/project/errors.py +56 -0
- snowflake/cli/api/project/project_verification.py +23 -0
- snowflake/cli/api/project/schemas/__init__.py +13 -0
- snowflake/cli/api/project/schemas/entities/application_entity.py +44 -0
- snowflake/cli/api/project/schemas/entities/application_package_entity.py +66 -0
- snowflake/cli/api/project/schemas/entities/common.py +78 -0
- snowflake/cli/api/project/schemas/entities/entities.py +30 -0
- snowflake/cli/api/project/schemas/identifier_model.py +49 -0
- snowflake/cli/api/project/schemas/native_app/__init__.py +13 -0
- snowflake/cli/api/project/schemas/native_app/application.py +62 -0
- snowflake/cli/api/project/schemas/native_app/native_app.py +93 -0
- snowflake/cli/api/project/schemas/native_app/package.py +78 -0
- snowflake/cli/api/project/schemas/native_app/path_mapping.py +65 -0
- snowflake/cli/api/project/schemas/project_definition.py +199 -0
- snowflake/cli/api/project/schemas/snowpark/__init__.py +13 -0
- snowflake/cli/api/project/schemas/snowpark/argument.py +28 -0
- snowflake/cli/api/project/schemas/snowpark/callable.py +69 -0
- snowflake/cli/api/project/schemas/snowpark/snowpark.py +36 -0
- snowflake/cli/api/project/schemas/streamlit/__init__.py +13 -0
- snowflake/cli/api/project/schemas/streamlit/streamlit.py +46 -0
- snowflake/cli/api/project/schemas/template.py +77 -0
- snowflake/cli/api/project/schemas/updatable_model.py +194 -0
- snowflake/cli/api/project/util.py +261 -0
- snowflake/cli/api/rendering/__init__.py +13 -0
- snowflake/cli/api/rendering/jinja.py +112 -0
- snowflake/cli/api/rendering/project_definition_templates.py +39 -0
- snowflake/cli/api/rendering/project_templates.py +98 -0
- snowflake/cli/api/rendering/sql_templates.py +60 -0
- snowflake/cli/api/rest_api.py +172 -0
- snowflake/cli/api/sanitizers.py +43 -0
- snowflake/cli/api/secure_path.py +362 -0
- snowflake/cli/api/secure_utils.py +29 -0
- snowflake/cli/api/sql_execution.py +260 -0
- snowflake/cli/api/utils/__init__.py +13 -0
- snowflake/cli/api/utils/cursor.py +34 -0
- snowflake/cli/api/utils/definition_rendering.py +383 -0
- snowflake/cli/api/utils/dict_utils.py +73 -0
- snowflake/cli/api/utils/error_handling.py +23 -0
- snowflake/cli/api/utils/graph.py +97 -0
- snowflake/cli/api/utils/models.py +63 -0
- snowflake/cli/api/utils/naming_utils.py +13 -0
- snowflake/cli/api/utils/path_utils.py +36 -0
- snowflake/cli/api/utils/templating_functions.py +144 -0
- snowflake/cli/api/utils/types.py +35 -0
- snowflake/cli/app/__init__.py +22 -0
- snowflake/cli/app/__main__.py +31 -0
- snowflake/cli/app/api_impl/__init__.py +13 -0
- snowflake/cli/app/api_impl/plugin/__init__.py +13 -0
- snowflake/cli/app/api_impl/plugin/plugin_config_provider_impl.py +66 -0
- snowflake/cli/app/build_and_push.sh +8 -0
- snowflake/cli/app/cli_app.py +243 -0
- snowflake/cli/app/commands_registration/__init__.py +33 -0
- snowflake/cli/app/commands_registration/builtin_plugins.py +54 -0
- snowflake/cli/app/commands_registration/command_plugins_loader.py +169 -0
- snowflake/cli/app/commands_registration/commands_registration_with_callbacks.py +105 -0
- snowflake/cli/app/commands_registration/exception_logging.py +26 -0
- snowflake/cli/app/commands_registration/threadsafe.py +48 -0
- snowflake/cli/app/commands_registration/typer_registration.py +153 -0
- snowflake/cli/app/constants.py +19 -0
- snowflake/cli/app/dev/__init__.py +13 -0
- snowflake/cli/app/dev/commands_structure.py +48 -0
- snowflake/cli/app/dev/docs/__init__.py +13 -0
- snowflake/cli/app/dev/docs/commands_docs_generator.py +100 -0
- snowflake/cli/app/dev/docs/generator.py +35 -0
- snowflake/cli/app/dev/docs/project_definition_docs_generator.py +58 -0
- snowflake/cli/app/dev/docs/project_definition_generate_json_schema.py +227 -0
- snowflake/cli/app/dev/docs/template_utils.py +23 -0
- snowflake/cli/app/dev/docs/templates/definition_description.rst.jinja2 +38 -0
- snowflake/cli/app/dev/docs/templates/overview.rst.jinja2 +9 -0
- snowflake/cli/app/dev/docs/templates/usage.rst.jinja2 +57 -0
- snowflake/cli/app/dev/pycharm_remote_debug.py +46 -0
- snowflake/cli/app/loggers.py +199 -0
- snowflake/cli/app/main_typer.py +62 -0
- snowflake/cli/app/printing.py +181 -0
- snowflake/cli/app/snow_connector.py +243 -0
- snowflake/cli/app/telemetry.py +189 -0
- snowflake/cli/plugins/__init__.py +13 -0
- snowflake/cli/plugins/connection/__init__.py +13 -0
- snowflake/cli/plugins/connection/commands.py +330 -0
- snowflake/cli/plugins/connection/plugin_spec.py +30 -0
- snowflake/cli/plugins/connection/util.py +179 -0
- snowflake/cli/plugins/cortex/__init__.py +13 -0
- snowflake/cli/plugins/cortex/commands.py +327 -0
- snowflake/cli/plugins/cortex/constants.py +17 -0
- snowflake/cli/plugins/cortex/manager.py +189 -0
- snowflake/cli/plugins/cortex/plugin_spec.py +30 -0
- snowflake/cli/plugins/cortex/types.py +22 -0
- snowflake/cli/plugins/git/__init__.py +13 -0
- snowflake/cli/plugins/git/commands.py +354 -0
- snowflake/cli/plugins/git/manager.py +105 -0
- snowflake/cli/plugins/git/plugin_spec.py +30 -0
- snowflake/cli/plugins/init/__init__.py +13 -0
- snowflake/cli/plugins/init/commands.py +248 -0
- snowflake/cli/plugins/init/plugin_spec.py +30 -0
- snowflake/cli/plugins/nativeapp/__init__.py +13 -0
- snowflake/cli/plugins/nativeapp/artifacts.py +742 -0
- snowflake/cli/plugins/nativeapp/codegen/__init__.py +13 -0
- snowflake/cli/plugins/nativeapp/codegen/artifact_processor.py +91 -0
- snowflake/cli/plugins/nativeapp/codegen/compiler.py +130 -0
- snowflake/cli/plugins/nativeapp/codegen/sandbox.py +306 -0
- 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/callback_source.py.jinja +181 -0
- snowflake/cli/plugins/nativeapp/codegen/snowpark/extension_function_utils.py +217 -0
- snowflake/cli/plugins/nativeapp/codegen/snowpark/models.py +61 -0
- snowflake/cli/plugins/nativeapp/codegen/snowpark/python_processor.py +528 -0
- snowflake/cli/plugins/nativeapp/commands.py +439 -0
- snowflake/cli/plugins/nativeapp/common_flags.py +44 -0
- snowflake/cli/plugins/nativeapp/constants.py +27 -0
- snowflake/cli/plugins/nativeapp/exceptions.py +122 -0
- snowflake/cli/plugins/nativeapp/feature_flags.py +24 -0
- snowflake/cli/plugins/nativeapp/init.py +345 -0
- snowflake/cli/plugins/nativeapp/manager.py +823 -0
- snowflake/cli/plugins/nativeapp/plugin_spec.py +30 -0
- snowflake/cli/plugins/nativeapp/policy.py +50 -0
- snowflake/cli/plugins/nativeapp/project_model.py +195 -0
- snowflake/cli/plugins/nativeapp/run_processor.py +389 -0
- snowflake/cli/plugins/nativeapp/teardown_processor.py +301 -0
- snowflake/cli/plugins/nativeapp/utils.py +98 -0
- snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +135 -0
- snowflake/cli/plugins/nativeapp/version/__init__.py +13 -0
- snowflake/cli/plugins/nativeapp/version/commands.py +170 -0
- snowflake/cli/plugins/nativeapp/version/version_processor.py +362 -0
- snowflake/cli/plugins/notebook/__init__.py +13 -0
- snowflake/cli/plugins/notebook/commands.py +85 -0
- snowflake/cli/plugins/notebook/exceptions.py +20 -0
- snowflake/cli/plugins/notebook/manager.py +71 -0
- snowflake/cli/plugins/notebook/plugin_spec.py +30 -0
- snowflake/cli/plugins/notebook/types.py +15 -0
- snowflake/cli/plugins/object/__init__.py +13 -0
- snowflake/cli/plugins/object/command_aliases.py +95 -0
- snowflake/cli/plugins/object/commands.py +181 -0
- snowflake/cli/plugins/object/common.py +85 -0
- snowflake/cli/plugins/object/manager.py +97 -0
- snowflake/cli/plugins/object/plugin_spec.py +30 -0
- snowflake/cli/plugins/object_stage_deprecated/__init__.py +15 -0
- snowflake/cli/plugins/object_stage_deprecated/commands.py +122 -0
- snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +32 -0
- snowflake/cli/plugins/snowpark/__init__.py +13 -0
- snowflake/cli/plugins/snowpark/commands.py +546 -0
- snowflake/cli/plugins/snowpark/common.py +307 -0
- snowflake/cli/plugins/snowpark/manager.py +109 -0
- snowflake/cli/plugins/snowpark/models.py +157 -0
- snowflake/cli/plugins/snowpark/package/__init__.py +13 -0
- snowflake/cli/plugins/snowpark/package/anaconda_packages.py +233 -0
- snowflake/cli/plugins/snowpark/package/commands.py +256 -0
- snowflake/cli/plugins/snowpark/package/manager.py +44 -0
- snowflake/cli/plugins/snowpark/package/utils.py +26 -0
- snowflake/cli/plugins/snowpark/package_utils.py +354 -0
- snowflake/cli/plugins/snowpark/plugin_spec.py +30 -0
- snowflake/cli/plugins/snowpark/snowpark_package_paths.py +65 -0
- snowflake/cli/plugins/snowpark/snowpark_shared.py +95 -0
- snowflake/cli/plugins/snowpark/zipper.py +81 -0
- snowflake/cli/plugins/spcs/__init__.py +35 -0
- snowflake/cli/plugins/spcs/common.py +99 -0
- snowflake/cli/plugins/spcs/compute_pool/__init__.py +13 -0
- snowflake/cli/plugins/spcs/compute_pool/commands.py +241 -0
- snowflake/cli/plugins/spcs/compute_pool/manager.py +121 -0
- snowflake/cli/plugins/spcs/image_registry/__init__.py +13 -0
- snowflake/cli/plugins/spcs/image_registry/commands.py +65 -0
- snowflake/cli/plugins/spcs/image_registry/manager.py +105 -0
- snowflake/cli/plugins/spcs/image_repository/__init__.py +13 -0
- snowflake/cli/plugins/spcs/image_repository/commands.py +202 -0
- snowflake/cli/plugins/spcs/image_repository/manager.py +84 -0
- snowflake/cli/plugins/spcs/jobs/__init__.py +13 -0
- snowflake/cli/plugins/spcs/jobs/commands.py +78 -0
- snowflake/cli/plugins/spcs/jobs/manager.py +53 -0
- snowflake/cli/plugins/spcs/plugin_spec.py +30 -0
- snowflake/cli/plugins/spcs/services/__init__.py +13 -0
- snowflake/cli/plugins/spcs/services/commands.py +312 -0
- snowflake/cli/plugins/spcs/services/manager.py +170 -0
- snowflake/cli/plugins/sql/__init__.py +13 -0
- snowflake/cli/plugins/sql/commands.py +83 -0
- snowflake/cli/plugins/sql/manager.py +92 -0
- snowflake/cli/plugins/sql/plugin_spec.py +30 -0
- snowflake/cli/plugins/sql/snowsql_templating.py +28 -0
- snowflake/cli/plugins/stage/__init__.py +13 -0
- snowflake/cli/plugins/stage/commands.py +263 -0
- snowflake/cli/plugins/stage/diff.py +326 -0
- snowflake/cli/plugins/stage/manager.py +577 -0
- snowflake/cli/plugins/stage/md5.py +160 -0
- snowflake/cli/plugins/stage/plugin_spec.py +30 -0
- snowflake/cli/plugins/streamlit/__init__.py +13 -0
- snowflake/cli/plugins/streamlit/commands.py +179 -0
- snowflake/cli/plugins/streamlit/manager.py +222 -0
- snowflake/cli/plugins/streamlit/plugin_spec.py +30 -0
- 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/.gitignore +4 -0
- snowflake/cli/templates/default_snowpark/app/__init__.py +0 -0
- snowflake/cli/templates/default_snowpark/app/common.py +2 -0
- snowflake/cli/templates/default_snowpark/app/functions.py +15 -0
- snowflake/cli/templates/default_snowpark/app/procedures.py +22 -0
- snowflake/cli/templates/default_snowpark/requirements.txt +1 -0
- snowflake/cli/templates/default_snowpark/snowflake.yml +23 -0
- snowflake/cli/templates/default_streamlit/.gitignore +4 -0
- snowflake/cli/templates/default_streamlit/common/hello.py +2 -0
- snowflake/cli/templates/default_streamlit/environment.yml +6 -0
- snowflake/cli/templates/default_streamlit/pages/my_page.py +3 -0
- snowflake/cli/templates/default_streamlit/snowflake.yml +10 -0
- snowflake/cli/templates/default_streamlit/streamlit_app.py +4 -0
- snowflake_cli-2.8.2.dist-info/METADATA +325 -0
- snowflake_cli-2.8.2.dist-info/RECORD +240 -0
- snowflake_cli-2.8.2.dist-info/WHEEL +4 -0
- snowflake_cli-2.8.2.dist-info/entry_points.txt +2 -0
- snowflake_cli-2.8.2.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,662 @@
|
|
|
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
|
+
import tempfile
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
from enum import Enum
|
|
20
|
+
from inspect import signature
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from typing import Any, Callable, List, Optional, Tuple
|
|
23
|
+
|
|
24
|
+
import click
|
|
25
|
+
import typer
|
|
26
|
+
from click import ClickException
|
|
27
|
+
from snowflake.cli.api.cli_global_context import cli_context_manager
|
|
28
|
+
from snowflake.cli.api.commands.typer_pre_execute import register_pre_execute_command
|
|
29
|
+
from snowflake.cli.api.console import cli_console
|
|
30
|
+
from snowflake.cli.api.exceptions import MissingConfiguration
|
|
31
|
+
from snowflake.cli.api.identifiers import FQN
|
|
32
|
+
from snowflake.cli.api.output.formats import OutputFormat
|
|
33
|
+
from snowflake.cli.api.project.definition_manager import DefinitionManager
|
|
34
|
+
from snowflake.cli.api.rendering.jinja import CONTEXT_KEY
|
|
35
|
+
|
|
36
|
+
DEFAULT_CONTEXT_SETTINGS = {"help_option_names": ["--help", "-h"]}
|
|
37
|
+
|
|
38
|
+
_CONNECTION_SECTION = "Connection configuration"
|
|
39
|
+
_CLI_BEHAVIOUR = "Global configuration"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class OnErrorType(Enum):
|
|
43
|
+
BREAK = "break"
|
|
44
|
+
CONTINUE = "continue"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class OverrideableOption:
|
|
48
|
+
"""
|
|
49
|
+
Class that allows you to generate instances of typer.models.OptionInfo with some default properties while allowing
|
|
50
|
+
specific values to be overridden.
|
|
51
|
+
|
|
52
|
+
Custom parameters:
|
|
53
|
+
- mutually_exclusive (Tuple[str]|List[str]): A list of parameter names that this Option is not compatible with. If this Option has
|
|
54
|
+
a truthy value and any of the other parameters in the mutually_exclusive list has a truthy value, a
|
|
55
|
+
ClickException will be thrown. Note that mutually_exclusive can contain an option's own name but does not require
|
|
56
|
+
it.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def __init__(
|
|
60
|
+
self,
|
|
61
|
+
default: Any,
|
|
62
|
+
*param_decls: str,
|
|
63
|
+
mutually_exclusive: Optional[List[str] | Tuple[str]] = None,
|
|
64
|
+
**kwargs,
|
|
65
|
+
):
|
|
66
|
+
self.default = default
|
|
67
|
+
self.param_decls = param_decls
|
|
68
|
+
self.mutually_exclusive = mutually_exclusive
|
|
69
|
+
self.kwargs = kwargs
|
|
70
|
+
|
|
71
|
+
def __call__(self, **kwargs) -> typer.models.OptionInfo:
|
|
72
|
+
"""
|
|
73
|
+
Returns a typer.models.OptionInfo instance initialized with the specified default values along with any overrides
|
|
74
|
+
from kwargs. Note that if you are overriding param_decls, you must pass an iterable of strings, you cannot use
|
|
75
|
+
positional arguments like you can with typer.Option. Does not modify the original instance.
|
|
76
|
+
"""
|
|
77
|
+
default = kwargs.get("default", self.default)
|
|
78
|
+
param_decls = kwargs.get("param_decls", self.param_decls)
|
|
79
|
+
mutually_exclusive = kwargs.get("mutually_exclusive", self.mutually_exclusive)
|
|
80
|
+
if not isinstance(param_decls, list) and not isinstance(param_decls, tuple):
|
|
81
|
+
raise TypeError("param_decls must be a list or tuple")
|
|
82
|
+
passed_kwargs = self.kwargs.copy()
|
|
83
|
+
passed_kwargs.update(kwargs)
|
|
84
|
+
if passed_kwargs.get("callback", None) or mutually_exclusive:
|
|
85
|
+
passed_kwargs["callback"] = self._callback_factory(
|
|
86
|
+
passed_kwargs.get("callback", None), mutually_exclusive
|
|
87
|
+
)
|
|
88
|
+
for non_kwarg in ["default", "param_decls", "mutually_exclusive"]:
|
|
89
|
+
passed_kwargs.pop(non_kwarg, None)
|
|
90
|
+
return typer.Option(default, *param_decls, **passed_kwargs)
|
|
91
|
+
|
|
92
|
+
class InvalidCallbackSignature(ClickException):
|
|
93
|
+
def __init__(self, callback):
|
|
94
|
+
super().__init__(
|
|
95
|
+
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)"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def _callback_factory(
|
|
99
|
+
self, callback, mutually_exclusive: Optional[List[str] | Tuple[str]]
|
|
100
|
+
):
|
|
101
|
+
callback = callback if callback else lambda x: x
|
|
102
|
+
|
|
103
|
+
# inspect existing_callback to make sure signature is valid
|
|
104
|
+
existing_params = signature(callback).parameters
|
|
105
|
+
# at most one parameter with each type in [typer.Context, typer.CallbackParam, any other type]
|
|
106
|
+
limits = [
|
|
107
|
+
lambda x: x == typer.Context,
|
|
108
|
+
lambda x: x == typer.CallbackParam,
|
|
109
|
+
lambda x: x != typer.Context and x != typer.CallbackParam,
|
|
110
|
+
]
|
|
111
|
+
for limit in limits:
|
|
112
|
+
if len([v for v in existing_params.values() if limit(v.annotation)]) > 1:
|
|
113
|
+
raise self.InvalidCallbackSignature(callback)
|
|
114
|
+
|
|
115
|
+
def generated_callback(ctx: typer.Context, param: typer.CallbackParam, value):
|
|
116
|
+
if mutually_exclusive:
|
|
117
|
+
for name in mutually_exclusive:
|
|
118
|
+
if value and ctx.params.get(
|
|
119
|
+
name, False
|
|
120
|
+
): # if the current parameter is set to True and a previous parameter is also Truthy
|
|
121
|
+
curr_opt = param.opts[0]
|
|
122
|
+
other_opt = [x for x in ctx.command.params if x.name == name][
|
|
123
|
+
0
|
|
124
|
+
].opts[0]
|
|
125
|
+
raise click.ClickException(
|
|
126
|
+
f"Options '{curr_opt}' and '{other_opt}' are incompatible."
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# pass args to existing callback based on its signature (this is how Typer infers callback args)
|
|
130
|
+
passed_params = {}
|
|
131
|
+
for existing_param in existing_params:
|
|
132
|
+
annotation = existing_params[existing_param].annotation
|
|
133
|
+
if annotation == typer.Context:
|
|
134
|
+
passed_params[existing_param] = ctx
|
|
135
|
+
elif annotation == typer.CallbackParam:
|
|
136
|
+
passed_params[existing_param] = param
|
|
137
|
+
else:
|
|
138
|
+
passed_params[existing_param] = value
|
|
139
|
+
return callback(**passed_params)
|
|
140
|
+
|
|
141
|
+
return generated_callback
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
from snowflake.cli.api.config import get_all_connections
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _callback(provide_setter: Callable[[], Callable[[Any], Any]]):
|
|
148
|
+
def callback(value):
|
|
149
|
+
set_value = provide_setter()
|
|
150
|
+
set_value(value)
|
|
151
|
+
return value
|
|
152
|
+
|
|
153
|
+
return callback
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
ConnectionOption = typer.Option(
|
|
157
|
+
None,
|
|
158
|
+
"--connection",
|
|
159
|
+
"-c",
|
|
160
|
+
"--environment",
|
|
161
|
+
help=f"Name of the connection, as defined in your `config.toml`. Default: `default`.",
|
|
162
|
+
callback=_callback(
|
|
163
|
+
lambda: cli_context_manager.connection_context.set_connection_name
|
|
164
|
+
),
|
|
165
|
+
show_default=False,
|
|
166
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
167
|
+
autocompletion=lambda: list(get_all_connections()),
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
TemporaryConnectionOption = typer.Option(
|
|
171
|
+
False,
|
|
172
|
+
"--temporary-connection",
|
|
173
|
+
"-x",
|
|
174
|
+
help="Uses connection defined with command line parameters, instead of one defined in config",
|
|
175
|
+
callback=_callback(
|
|
176
|
+
lambda: cli_context_manager.connection_context.set_temporary_connection
|
|
177
|
+
),
|
|
178
|
+
is_flag=True,
|
|
179
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
AccountOption = typer.Option(
|
|
183
|
+
None,
|
|
184
|
+
"--account",
|
|
185
|
+
"--accountname",
|
|
186
|
+
help="Name assigned to your Snowflake account. Overrides the value specified for the connection.",
|
|
187
|
+
callback=_callback(lambda: cli_context_manager.connection_context.set_account),
|
|
188
|
+
show_default=False,
|
|
189
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
UserOption = typer.Option(
|
|
193
|
+
None,
|
|
194
|
+
"--user",
|
|
195
|
+
"--username",
|
|
196
|
+
help="Username to connect to Snowflake. Overrides the value specified for the connection.",
|
|
197
|
+
callback=_callback(lambda: cli_context_manager.connection_context.set_user),
|
|
198
|
+
show_default=False,
|
|
199
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
PLAIN_PASSWORD_MSG = "WARNING! Using --password via the CLI is insecure. Use environment variables instead."
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _password_callback(value: str):
|
|
207
|
+
if value:
|
|
208
|
+
cli_console.message(PLAIN_PASSWORD_MSG)
|
|
209
|
+
|
|
210
|
+
return _callback(lambda: cli_context_manager.connection_context.set_password)(value)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
PasswordOption = typer.Option(
|
|
214
|
+
None,
|
|
215
|
+
"--password",
|
|
216
|
+
help="Snowflake password. Overrides the value specified for the connection.",
|
|
217
|
+
hide_input=True,
|
|
218
|
+
callback=_password_callback,
|
|
219
|
+
show_default=False,
|
|
220
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
AuthenticatorOption = typer.Option(
|
|
224
|
+
None,
|
|
225
|
+
"--authenticator",
|
|
226
|
+
help="Snowflake authenticator. Overrides the value specified for the connection.",
|
|
227
|
+
hide_input=True,
|
|
228
|
+
callback=_callback(
|
|
229
|
+
lambda: cli_context_manager.connection_context.set_authenticator
|
|
230
|
+
),
|
|
231
|
+
show_default=False,
|
|
232
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
PrivateKeyPathOption = typer.Option(
|
|
236
|
+
None,
|
|
237
|
+
"--private-key-path",
|
|
238
|
+
help="Snowflake private key path. Overrides the value specified for the connection.",
|
|
239
|
+
hide_input=True,
|
|
240
|
+
callback=_callback(
|
|
241
|
+
lambda: cli_context_manager.connection_context.set_private_key_path
|
|
242
|
+
),
|
|
243
|
+
show_default=False,
|
|
244
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
245
|
+
exists=True,
|
|
246
|
+
file_okay=True,
|
|
247
|
+
dir_okay=False,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
SessionTokenOption = typer.Option(
|
|
251
|
+
None,
|
|
252
|
+
"--session-token",
|
|
253
|
+
help="Snowflake session token. Can be used only in conjunction with --master-token. Overrides the value specified for the connection.",
|
|
254
|
+
hide_input=True,
|
|
255
|
+
callback=_callback(
|
|
256
|
+
lambda: cli_context_manager.connection_context.set_session_token
|
|
257
|
+
),
|
|
258
|
+
show_default=False,
|
|
259
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
260
|
+
exists=True,
|
|
261
|
+
file_okay=True,
|
|
262
|
+
dir_okay=False,
|
|
263
|
+
hidden=True,
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
MasterTokenOption = typer.Option(
|
|
267
|
+
None,
|
|
268
|
+
"--master-token",
|
|
269
|
+
help="Snowflake master token. Can be used only in conjunction with --session-token. Overrides the value specified for the connection.",
|
|
270
|
+
hide_input=True,
|
|
271
|
+
callback=_callback(lambda: cli_context_manager.connection_context.set_master_token),
|
|
272
|
+
show_default=False,
|
|
273
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
274
|
+
exists=True,
|
|
275
|
+
file_okay=True,
|
|
276
|
+
dir_okay=False,
|
|
277
|
+
hidden=True,
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
TokenFilePathOption = typer.Option(
|
|
281
|
+
None,
|
|
282
|
+
"--token-file-path",
|
|
283
|
+
help="Path to file with an OAuth token that should be used when connecting to Snowflake",
|
|
284
|
+
callback=_callback(
|
|
285
|
+
lambda: cli_context_manager.connection_context.set_token_file_path
|
|
286
|
+
),
|
|
287
|
+
show_default=False,
|
|
288
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
289
|
+
exists=True,
|
|
290
|
+
file_okay=True,
|
|
291
|
+
dir_okay=False,
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
DatabaseOption = typer.Option(
|
|
295
|
+
None,
|
|
296
|
+
"--database",
|
|
297
|
+
"--dbname",
|
|
298
|
+
help="Database to use. Overrides the value specified for the connection.",
|
|
299
|
+
callback=_callback(lambda: cli_context_manager.connection_context.set_database),
|
|
300
|
+
show_default=False,
|
|
301
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
SchemaOption = typer.Option(
|
|
305
|
+
None,
|
|
306
|
+
"--schema",
|
|
307
|
+
"--schemaname",
|
|
308
|
+
help="Database schema to use. Overrides the value specified for the connection.",
|
|
309
|
+
callback=_callback(lambda: cli_context_manager.connection_context.set_schema),
|
|
310
|
+
show_default=False,
|
|
311
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
RoleOption = typer.Option(
|
|
315
|
+
None,
|
|
316
|
+
"--role",
|
|
317
|
+
"--rolename",
|
|
318
|
+
help="Role to use. Overrides the value specified for the connection.",
|
|
319
|
+
callback=_callback(lambda: cli_context_manager.connection_context.set_role),
|
|
320
|
+
show_default=False,
|
|
321
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
WarehouseOption = typer.Option(
|
|
325
|
+
None,
|
|
326
|
+
"--warehouse",
|
|
327
|
+
help="Warehouse to use. Overrides the value specified for the connection.",
|
|
328
|
+
callback=_callback(lambda: cli_context_manager.connection_context.set_warehouse),
|
|
329
|
+
show_default=False,
|
|
330
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
MfaPasscodeOption = typer.Option(
|
|
334
|
+
None,
|
|
335
|
+
"--mfa-passcode",
|
|
336
|
+
help="Token to use for multi-factor authentication (MFA)",
|
|
337
|
+
callback=_callback(lambda: cli_context_manager.connection_context.set_mfa_passcode),
|
|
338
|
+
prompt="MFA passcode",
|
|
339
|
+
prompt_required=False,
|
|
340
|
+
show_default=False,
|
|
341
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
EnableDiagOption = typer.Option(
|
|
345
|
+
False,
|
|
346
|
+
"--enable-diag",
|
|
347
|
+
help="Run python connector diagnostic test",
|
|
348
|
+
callback=_callback(lambda: cli_context_manager.connection_context.set_enable_diag),
|
|
349
|
+
show_default=False,
|
|
350
|
+
is_flag=True,
|
|
351
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
# Set default via callback to avoid including tempdir path in generated docs (snow --docs).
|
|
355
|
+
# Use constant instead of None, as None is removed from telemetry data.
|
|
356
|
+
_DIAG_LOG_DEFAULT_VALUE = "<temporary_directory>"
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def _diag_log_path_callback(path: str):
|
|
360
|
+
if path == _DIAG_LOG_DEFAULT_VALUE:
|
|
361
|
+
path = tempfile.gettempdir()
|
|
362
|
+
cli_context_manager.connection_context.set_diag_log_path(Path(path))
|
|
363
|
+
return path
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
DiagLogPathOption: Path = typer.Option(
|
|
367
|
+
tempfile.gettempdir(),
|
|
368
|
+
"--diag-log-path",
|
|
369
|
+
help="Diagnostic report path",
|
|
370
|
+
callback=_diag_log_path_callback,
|
|
371
|
+
show_default=False,
|
|
372
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
373
|
+
exists=True,
|
|
374
|
+
writable=True,
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
DiagAllowlistPathOption: Path = typer.Option(
|
|
378
|
+
None,
|
|
379
|
+
"--diag-allowlist-path",
|
|
380
|
+
help="Diagnostic report path to optional allowlist",
|
|
381
|
+
callback=_callback(
|
|
382
|
+
lambda: cli_context_manager.connection_context.set_diag_allowlist_path
|
|
383
|
+
),
|
|
384
|
+
show_default=False,
|
|
385
|
+
rich_help_panel=_CONNECTION_SECTION,
|
|
386
|
+
exists=True,
|
|
387
|
+
file_okay=True,
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
OutputFormatOption = typer.Option(
|
|
391
|
+
OutputFormat.TABLE.value,
|
|
392
|
+
"--format",
|
|
393
|
+
help="Specifies the output format.",
|
|
394
|
+
case_sensitive=False,
|
|
395
|
+
callback=_callback(lambda: cli_context_manager.set_output_format),
|
|
396
|
+
rich_help_panel=_CLI_BEHAVIOUR,
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
SilentOption = typer.Option(
|
|
400
|
+
False,
|
|
401
|
+
"--silent",
|
|
402
|
+
help="Turns off intermediate output to console.",
|
|
403
|
+
callback=_callback(lambda: cli_context_manager.set_silent),
|
|
404
|
+
is_flag=True,
|
|
405
|
+
rich_help_panel=_CLI_BEHAVIOUR,
|
|
406
|
+
is_eager=True,
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
VerboseOption = typer.Option(
|
|
410
|
+
False,
|
|
411
|
+
"--verbose",
|
|
412
|
+
"-v",
|
|
413
|
+
help="Displays log entries for log levels `info` and higher.",
|
|
414
|
+
callback=_callback(lambda: cli_context_manager.set_verbose),
|
|
415
|
+
is_flag=True,
|
|
416
|
+
rich_help_panel=_CLI_BEHAVIOUR,
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
DebugOption = typer.Option(
|
|
420
|
+
False,
|
|
421
|
+
"--debug",
|
|
422
|
+
help="Displays log entries for log levels `debug` and higher; debug logs contains additional information.",
|
|
423
|
+
callback=_callback(lambda: cli_context_manager.set_enable_tracebacks),
|
|
424
|
+
is_flag=True,
|
|
425
|
+
rich_help_panel=_CLI_BEHAVIOUR,
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
# If IfExistsOption, IfNotExistsOption, or ReplaceOption are used with names other than those in CREATE_MODE_OPTION_NAMES,
|
|
430
|
+
# you must also override mutually_exclusive if you want to retain the validation that at most one of these flags is
|
|
431
|
+
# passed.
|
|
432
|
+
CREATE_MODE_OPTION_NAMES = ["if_exists", "if_not_exists", "replace"]
|
|
433
|
+
|
|
434
|
+
IfExistsOption = OverrideableOption(
|
|
435
|
+
False,
|
|
436
|
+
"--if-exists",
|
|
437
|
+
help="Only apply this operation if the specified object exists.",
|
|
438
|
+
mutually_exclusive=CREATE_MODE_OPTION_NAMES,
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
IfNotExistsOption = OverrideableOption(
|
|
442
|
+
False,
|
|
443
|
+
"--if-not-exists",
|
|
444
|
+
help="Only apply this operation if the specified object does not already exist.",
|
|
445
|
+
mutually_exclusive=CREATE_MODE_OPTION_NAMES,
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
ReplaceOption = OverrideableOption(
|
|
449
|
+
False,
|
|
450
|
+
"--replace",
|
|
451
|
+
help="Replace this object if it already exists.",
|
|
452
|
+
mutually_exclusive=CREATE_MODE_OPTION_NAMES,
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
OnErrorOption = typer.Option(
|
|
456
|
+
OnErrorType.BREAK.value,
|
|
457
|
+
"--on-error",
|
|
458
|
+
help="What to do when an error occurs. Defaults to break.",
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
NoInteractiveOption = typer.Option(False, "--no-interactive", help="Disable prompting.")
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def variables_option(description: str):
|
|
465
|
+
return typer.Option(
|
|
466
|
+
None,
|
|
467
|
+
"--variable",
|
|
468
|
+
"-D",
|
|
469
|
+
help=description,
|
|
470
|
+
show_default=False,
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
ExecuteVariablesOption = variables_option(
|
|
475
|
+
'Variables for the execution context. For example: `-D "<key>=<value>"`. '
|
|
476
|
+
"For SQL files variables are use to expand the template and any unknown variable will cause an error. "
|
|
477
|
+
"For Python files variables are used to update os.environ dictionary. Provided keys are capitalized to adhere to best practices."
|
|
478
|
+
"In case of SQL files string values must be quoted in `''` (consider embedding quoting in the file).",
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def like_option(help_example: str):
|
|
483
|
+
return typer.Option(
|
|
484
|
+
"%%",
|
|
485
|
+
"--like",
|
|
486
|
+
"-l",
|
|
487
|
+
help=f"SQL LIKE pattern for filtering objects by name. For example, {help_example}.",
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
def _pattern_option_callback(value):
|
|
492
|
+
if value and value.count("'") != value.count("\\'"):
|
|
493
|
+
raise ClickException('All "\'" characters in PATTERN must be escaped: "\\\'"')
|
|
494
|
+
return value
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
PatternOption = typer.Option(
|
|
498
|
+
None,
|
|
499
|
+
"--pattern",
|
|
500
|
+
help=(
|
|
501
|
+
"Regex pattern for filtering files by name."
|
|
502
|
+
r' For example --pattern ".*\.txt" will filter only files with .txt extension.'
|
|
503
|
+
),
|
|
504
|
+
show_default=False,
|
|
505
|
+
callback=_pattern_option_callback,
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def experimental_option(
|
|
510
|
+
experimental_behaviour_description: Optional[str] = None,
|
|
511
|
+
) -> typer.Option:
|
|
512
|
+
help_text = (
|
|
513
|
+
f"Turns on experimental behaviour of the command: {experimental_behaviour_description}"
|
|
514
|
+
if experimental_behaviour_description
|
|
515
|
+
else "Turns on experimental behaviour of the command."
|
|
516
|
+
)
|
|
517
|
+
return typer.Option(
|
|
518
|
+
False,
|
|
519
|
+
"--experimental",
|
|
520
|
+
help=help_text,
|
|
521
|
+
hidden=True,
|
|
522
|
+
callback=_callback(lambda: cli_context_manager.set_experimental),
|
|
523
|
+
is_flag=True,
|
|
524
|
+
rich_help_panel=_CLI_BEHAVIOUR,
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
def identifier_argument(
|
|
529
|
+
sf_object: str, example: str, callback: Callable | None = None
|
|
530
|
+
) -> typer.Argument:
|
|
531
|
+
return typer.Argument(
|
|
532
|
+
...,
|
|
533
|
+
help=f"Identifier of the {sf_object}. For example: {example}",
|
|
534
|
+
show_default=False,
|
|
535
|
+
click_type=IdentifierType(),
|
|
536
|
+
callback=callback,
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
def execution_identifier_argument(sf_object: str, example: str) -> typer.Argument:
|
|
541
|
+
return typer.Argument(
|
|
542
|
+
...,
|
|
543
|
+
help=f"Execution identifier of the {sf_object}. For example: {example}",
|
|
544
|
+
show_default=False,
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
def register_project_definition(is_optional: bool) -> None:
|
|
549
|
+
project_path = cli_context_manager.project_path_arg
|
|
550
|
+
env_overrides_args = cli_context_manager.project_env_overrides_args
|
|
551
|
+
|
|
552
|
+
dm = DefinitionManager(project_path, {CONTEXT_KEY: {"env": env_overrides_args}})
|
|
553
|
+
project_definition = dm.project_definition
|
|
554
|
+
project_root = dm.project_root
|
|
555
|
+
template_context = dm.template_context
|
|
556
|
+
|
|
557
|
+
if not dm.has_definition_file and not is_optional:
|
|
558
|
+
raise MissingConfiguration(
|
|
559
|
+
"Cannot find project definition (snowflake.yml). Please provide a path to the project or run this command in a valid project directory."
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
cli_context_manager.set_project_definition(project_definition)
|
|
563
|
+
cli_context_manager.set_project_root(project_root)
|
|
564
|
+
cli_context_manager.set_template_context(template_context)
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
def project_definition_option(is_optional: bool):
|
|
568
|
+
def project_definition_callback(project_path: str) -> None:
|
|
569
|
+
cli_context_manager.set_project_path_arg(project_path)
|
|
570
|
+
register_pre_execute_command(lambda: register_project_definition(is_optional))
|
|
571
|
+
|
|
572
|
+
return typer.Option(
|
|
573
|
+
None,
|
|
574
|
+
"-p",
|
|
575
|
+
"--project",
|
|
576
|
+
help=f"Path where Snowflake project resides. "
|
|
577
|
+
f"Defaults to current working directory.",
|
|
578
|
+
callback=_callback(lambda: project_definition_callback),
|
|
579
|
+
show_default=False,
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
def project_env_overrides_option():
|
|
584
|
+
def project_env_overrides_callback(env_overrides_args_list: list[str]) -> None:
|
|
585
|
+
env_overrides_args_map = {
|
|
586
|
+
v.key: v.value for v in parse_key_value_variables(env_overrides_args_list)
|
|
587
|
+
}
|
|
588
|
+
cli_context_manager.set_project_env_overrides_args(env_overrides_args_map)
|
|
589
|
+
|
|
590
|
+
return typer.Option(
|
|
591
|
+
[],
|
|
592
|
+
"--env",
|
|
593
|
+
help="String in format of key=value. Overrides variables from env section used for templating.",
|
|
594
|
+
callback=_callback(lambda: project_env_overrides_callback),
|
|
595
|
+
show_default=False,
|
|
596
|
+
)
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
def readable_file_option(param_name: str, help_str: str) -> typer.Option:
|
|
600
|
+
return typer.Option(
|
|
601
|
+
None,
|
|
602
|
+
param_name,
|
|
603
|
+
exists=True,
|
|
604
|
+
file_okay=True,
|
|
605
|
+
dir_okay=False,
|
|
606
|
+
readable=True,
|
|
607
|
+
help=help_str,
|
|
608
|
+
show_default=False,
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
def deprecated_flag_callback(msg: str):
|
|
613
|
+
def _warning_callback(ctx: click.Context, param: click.Parameter, value: Any):
|
|
614
|
+
if ctx.get_parameter_source(param.name) != click.core.ParameterSource.DEFAULT: # type: ignore[attr-defined]
|
|
615
|
+
cli_console.warning(message=msg)
|
|
616
|
+
return value
|
|
617
|
+
|
|
618
|
+
return _warning_callback
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
def deprecated_flag_callback_enum(msg: str):
|
|
622
|
+
def _warning_callback(ctx: click.Context, param: click.Parameter, value: Any):
|
|
623
|
+
if ctx.get_parameter_source(param.name) != click.core.ParameterSource.DEFAULT: # type: ignore[attr-defined]
|
|
624
|
+
cli_console.warning(message=msg)
|
|
625
|
+
# Typer bug: enums passed through callback are turning into None,
|
|
626
|
+
# unless their explicit value is returned ¯\_(ツ)_/¯
|
|
627
|
+
return value.value
|
|
628
|
+
|
|
629
|
+
return _warning_callback
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
@dataclass
|
|
633
|
+
class Variable:
|
|
634
|
+
key: str
|
|
635
|
+
value: str
|
|
636
|
+
|
|
637
|
+
def __init__(self, key: str, value: str):
|
|
638
|
+
self.key = key
|
|
639
|
+
self.value = value
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
def parse_key_value_variables(variables: Optional[List[str]]) -> List[Variable]:
|
|
643
|
+
"""Util for parsing key=value input. Useful for commands accepting multiple input options."""
|
|
644
|
+
if not variables:
|
|
645
|
+
return []
|
|
646
|
+
result: List[Variable] = []
|
|
647
|
+
if not variables:
|
|
648
|
+
return result
|
|
649
|
+
for p in variables:
|
|
650
|
+
if "=" not in p:
|
|
651
|
+
raise ClickException(f"Invalid variable: '{p}'")
|
|
652
|
+
|
|
653
|
+
key, value = p.split("=", 1)
|
|
654
|
+
result.append(Variable(key.strip(), value.strip()))
|
|
655
|
+
return result
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
class IdentifierType(click.ParamType):
|
|
659
|
+
name = "TEXT"
|
|
660
|
+
|
|
661
|
+
def convert(self, value, param, ctx):
|
|
662
|
+
return FQN.from_string(value)
|