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.
Files changed (240) hide show
  1. snowflake/cli/__about__.py +17 -0
  2. snowflake/cli/__init__.py +13 -0
  3. snowflake/cli/api/__init__.py +48 -0
  4. snowflake/cli/api/cli_global_context.py +390 -0
  5. snowflake/cli/api/commands/__init__.py +13 -0
  6. snowflake/cli/api/commands/alias.py +23 -0
  7. snowflake/cli/api/commands/decorators.py +354 -0
  8. snowflake/cli/api/commands/execution_metadata.py +40 -0
  9. snowflake/cli/api/commands/experimental_behaviour.py +19 -0
  10. snowflake/cli/api/commands/flags.py +662 -0
  11. snowflake/cli/api/commands/project_initialisation.py +65 -0
  12. snowflake/cli/api/commands/snow_typer.py +237 -0
  13. snowflake/cli/api/commands/typer_pre_execute.py +26 -0
  14. snowflake/cli/api/config.py +348 -0
  15. snowflake/cli/api/console/__init__.py +17 -0
  16. snowflake/cli/api/console/abc.py +89 -0
  17. snowflake/cli/api/console/console.py +134 -0
  18. snowflake/cli/api/console/enum.py +17 -0
  19. snowflake/cli/api/constants.py +79 -0
  20. snowflake/cli/api/errno.py +27 -0
  21. snowflake/cli/api/exceptions.py +164 -0
  22. snowflake/cli/api/feature_flags.py +55 -0
  23. snowflake/cli/api/identifiers.py +167 -0
  24. snowflake/cli/api/output/__init__.py +13 -0
  25. snowflake/cli/api/output/formats.py +20 -0
  26. snowflake/cli/api/output/types.py +118 -0
  27. snowflake/cli/api/plugins/__init__.py +13 -0
  28. snowflake/cli/api/plugins/command/__init__.py +72 -0
  29. snowflake/cli/api/plugins/command/plugin_hook_specs.py +21 -0
  30. snowflake/cli/api/plugins/plugin_config.py +32 -0
  31. snowflake/cli/api/project/__init__.py +13 -0
  32. snowflake/cli/api/project/definition.py +84 -0
  33. snowflake/cli/api/project/definition_manager.py +134 -0
  34. snowflake/cli/api/project/errors.py +56 -0
  35. snowflake/cli/api/project/project_verification.py +23 -0
  36. snowflake/cli/api/project/schemas/__init__.py +13 -0
  37. snowflake/cli/api/project/schemas/entities/application_entity.py +44 -0
  38. snowflake/cli/api/project/schemas/entities/application_package_entity.py +66 -0
  39. snowflake/cli/api/project/schemas/entities/common.py +78 -0
  40. snowflake/cli/api/project/schemas/entities/entities.py +30 -0
  41. snowflake/cli/api/project/schemas/identifier_model.py +49 -0
  42. snowflake/cli/api/project/schemas/native_app/__init__.py +13 -0
  43. snowflake/cli/api/project/schemas/native_app/application.py +62 -0
  44. snowflake/cli/api/project/schemas/native_app/native_app.py +93 -0
  45. snowflake/cli/api/project/schemas/native_app/package.py +78 -0
  46. snowflake/cli/api/project/schemas/native_app/path_mapping.py +65 -0
  47. snowflake/cli/api/project/schemas/project_definition.py +199 -0
  48. snowflake/cli/api/project/schemas/snowpark/__init__.py +13 -0
  49. snowflake/cli/api/project/schemas/snowpark/argument.py +28 -0
  50. snowflake/cli/api/project/schemas/snowpark/callable.py +69 -0
  51. snowflake/cli/api/project/schemas/snowpark/snowpark.py +36 -0
  52. snowflake/cli/api/project/schemas/streamlit/__init__.py +13 -0
  53. snowflake/cli/api/project/schemas/streamlit/streamlit.py +46 -0
  54. snowflake/cli/api/project/schemas/template.py +77 -0
  55. snowflake/cli/api/project/schemas/updatable_model.py +194 -0
  56. snowflake/cli/api/project/util.py +261 -0
  57. snowflake/cli/api/rendering/__init__.py +13 -0
  58. snowflake/cli/api/rendering/jinja.py +112 -0
  59. snowflake/cli/api/rendering/project_definition_templates.py +39 -0
  60. snowflake/cli/api/rendering/project_templates.py +98 -0
  61. snowflake/cli/api/rendering/sql_templates.py +60 -0
  62. snowflake/cli/api/rest_api.py +172 -0
  63. snowflake/cli/api/sanitizers.py +43 -0
  64. snowflake/cli/api/secure_path.py +362 -0
  65. snowflake/cli/api/secure_utils.py +29 -0
  66. snowflake/cli/api/sql_execution.py +260 -0
  67. snowflake/cli/api/utils/__init__.py +13 -0
  68. snowflake/cli/api/utils/cursor.py +34 -0
  69. snowflake/cli/api/utils/definition_rendering.py +383 -0
  70. snowflake/cli/api/utils/dict_utils.py +73 -0
  71. snowflake/cli/api/utils/error_handling.py +23 -0
  72. snowflake/cli/api/utils/graph.py +97 -0
  73. snowflake/cli/api/utils/models.py +63 -0
  74. snowflake/cli/api/utils/naming_utils.py +13 -0
  75. snowflake/cli/api/utils/path_utils.py +36 -0
  76. snowflake/cli/api/utils/templating_functions.py +144 -0
  77. snowflake/cli/api/utils/types.py +35 -0
  78. snowflake/cli/app/__init__.py +22 -0
  79. snowflake/cli/app/__main__.py +31 -0
  80. snowflake/cli/app/api_impl/__init__.py +13 -0
  81. snowflake/cli/app/api_impl/plugin/__init__.py +13 -0
  82. snowflake/cli/app/api_impl/plugin/plugin_config_provider_impl.py +66 -0
  83. snowflake/cli/app/build_and_push.sh +8 -0
  84. snowflake/cli/app/cli_app.py +243 -0
  85. snowflake/cli/app/commands_registration/__init__.py +33 -0
  86. snowflake/cli/app/commands_registration/builtin_plugins.py +54 -0
  87. snowflake/cli/app/commands_registration/command_plugins_loader.py +169 -0
  88. snowflake/cli/app/commands_registration/commands_registration_with_callbacks.py +105 -0
  89. snowflake/cli/app/commands_registration/exception_logging.py +26 -0
  90. snowflake/cli/app/commands_registration/threadsafe.py +48 -0
  91. snowflake/cli/app/commands_registration/typer_registration.py +153 -0
  92. snowflake/cli/app/constants.py +19 -0
  93. snowflake/cli/app/dev/__init__.py +13 -0
  94. snowflake/cli/app/dev/commands_structure.py +48 -0
  95. snowflake/cli/app/dev/docs/__init__.py +13 -0
  96. snowflake/cli/app/dev/docs/commands_docs_generator.py +100 -0
  97. snowflake/cli/app/dev/docs/generator.py +35 -0
  98. snowflake/cli/app/dev/docs/project_definition_docs_generator.py +58 -0
  99. snowflake/cli/app/dev/docs/project_definition_generate_json_schema.py +227 -0
  100. snowflake/cli/app/dev/docs/template_utils.py +23 -0
  101. snowflake/cli/app/dev/docs/templates/definition_description.rst.jinja2 +38 -0
  102. snowflake/cli/app/dev/docs/templates/overview.rst.jinja2 +9 -0
  103. snowflake/cli/app/dev/docs/templates/usage.rst.jinja2 +57 -0
  104. snowflake/cli/app/dev/pycharm_remote_debug.py +46 -0
  105. snowflake/cli/app/loggers.py +199 -0
  106. snowflake/cli/app/main_typer.py +62 -0
  107. snowflake/cli/app/printing.py +181 -0
  108. snowflake/cli/app/snow_connector.py +243 -0
  109. snowflake/cli/app/telemetry.py +189 -0
  110. snowflake/cli/plugins/__init__.py +13 -0
  111. snowflake/cli/plugins/connection/__init__.py +13 -0
  112. snowflake/cli/plugins/connection/commands.py +330 -0
  113. snowflake/cli/plugins/connection/plugin_spec.py +30 -0
  114. snowflake/cli/plugins/connection/util.py +179 -0
  115. snowflake/cli/plugins/cortex/__init__.py +13 -0
  116. snowflake/cli/plugins/cortex/commands.py +327 -0
  117. snowflake/cli/plugins/cortex/constants.py +17 -0
  118. snowflake/cli/plugins/cortex/manager.py +189 -0
  119. snowflake/cli/plugins/cortex/plugin_spec.py +30 -0
  120. snowflake/cli/plugins/cortex/types.py +22 -0
  121. snowflake/cli/plugins/git/__init__.py +13 -0
  122. snowflake/cli/plugins/git/commands.py +354 -0
  123. snowflake/cli/plugins/git/manager.py +105 -0
  124. snowflake/cli/plugins/git/plugin_spec.py +30 -0
  125. snowflake/cli/plugins/init/__init__.py +13 -0
  126. snowflake/cli/plugins/init/commands.py +248 -0
  127. snowflake/cli/plugins/init/plugin_spec.py +30 -0
  128. snowflake/cli/plugins/nativeapp/__init__.py +13 -0
  129. snowflake/cli/plugins/nativeapp/artifacts.py +742 -0
  130. snowflake/cli/plugins/nativeapp/codegen/__init__.py +13 -0
  131. snowflake/cli/plugins/nativeapp/codegen/artifact_processor.py +91 -0
  132. snowflake/cli/plugins/nativeapp/codegen/compiler.py +130 -0
  133. snowflake/cli/plugins/nativeapp/codegen/sandbox.py +306 -0
  134. snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +172 -0
  135. snowflake/cli/plugins/nativeapp/codegen/setup/setup_driver.py.source +56 -0
  136. snowflake/cli/plugins/nativeapp/codegen/snowpark/callback_source.py.jinja +181 -0
  137. snowflake/cli/plugins/nativeapp/codegen/snowpark/extension_function_utils.py +217 -0
  138. snowflake/cli/plugins/nativeapp/codegen/snowpark/models.py +61 -0
  139. snowflake/cli/plugins/nativeapp/codegen/snowpark/python_processor.py +528 -0
  140. snowflake/cli/plugins/nativeapp/commands.py +439 -0
  141. snowflake/cli/plugins/nativeapp/common_flags.py +44 -0
  142. snowflake/cli/plugins/nativeapp/constants.py +27 -0
  143. snowflake/cli/plugins/nativeapp/exceptions.py +122 -0
  144. snowflake/cli/plugins/nativeapp/feature_flags.py +24 -0
  145. snowflake/cli/plugins/nativeapp/init.py +345 -0
  146. snowflake/cli/plugins/nativeapp/manager.py +823 -0
  147. snowflake/cli/plugins/nativeapp/plugin_spec.py +30 -0
  148. snowflake/cli/plugins/nativeapp/policy.py +50 -0
  149. snowflake/cli/plugins/nativeapp/project_model.py +195 -0
  150. snowflake/cli/plugins/nativeapp/run_processor.py +389 -0
  151. snowflake/cli/plugins/nativeapp/teardown_processor.py +301 -0
  152. snowflake/cli/plugins/nativeapp/utils.py +98 -0
  153. snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +135 -0
  154. snowflake/cli/plugins/nativeapp/version/__init__.py +13 -0
  155. snowflake/cli/plugins/nativeapp/version/commands.py +170 -0
  156. snowflake/cli/plugins/nativeapp/version/version_processor.py +362 -0
  157. snowflake/cli/plugins/notebook/__init__.py +13 -0
  158. snowflake/cli/plugins/notebook/commands.py +85 -0
  159. snowflake/cli/plugins/notebook/exceptions.py +20 -0
  160. snowflake/cli/plugins/notebook/manager.py +71 -0
  161. snowflake/cli/plugins/notebook/plugin_spec.py +30 -0
  162. snowflake/cli/plugins/notebook/types.py +15 -0
  163. snowflake/cli/plugins/object/__init__.py +13 -0
  164. snowflake/cli/plugins/object/command_aliases.py +95 -0
  165. snowflake/cli/plugins/object/commands.py +181 -0
  166. snowflake/cli/plugins/object/common.py +85 -0
  167. snowflake/cli/plugins/object/manager.py +97 -0
  168. snowflake/cli/plugins/object/plugin_spec.py +30 -0
  169. snowflake/cli/plugins/object_stage_deprecated/__init__.py +15 -0
  170. snowflake/cli/plugins/object_stage_deprecated/commands.py +122 -0
  171. snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +32 -0
  172. snowflake/cli/plugins/snowpark/__init__.py +13 -0
  173. snowflake/cli/plugins/snowpark/commands.py +546 -0
  174. snowflake/cli/plugins/snowpark/common.py +307 -0
  175. snowflake/cli/plugins/snowpark/manager.py +109 -0
  176. snowflake/cli/plugins/snowpark/models.py +157 -0
  177. snowflake/cli/plugins/snowpark/package/__init__.py +13 -0
  178. snowflake/cli/plugins/snowpark/package/anaconda_packages.py +233 -0
  179. snowflake/cli/plugins/snowpark/package/commands.py +256 -0
  180. snowflake/cli/plugins/snowpark/package/manager.py +44 -0
  181. snowflake/cli/plugins/snowpark/package/utils.py +26 -0
  182. snowflake/cli/plugins/snowpark/package_utils.py +354 -0
  183. snowflake/cli/plugins/snowpark/plugin_spec.py +30 -0
  184. snowflake/cli/plugins/snowpark/snowpark_package_paths.py +65 -0
  185. snowflake/cli/plugins/snowpark/snowpark_shared.py +95 -0
  186. snowflake/cli/plugins/snowpark/zipper.py +81 -0
  187. snowflake/cli/plugins/spcs/__init__.py +35 -0
  188. snowflake/cli/plugins/spcs/common.py +99 -0
  189. snowflake/cli/plugins/spcs/compute_pool/__init__.py +13 -0
  190. snowflake/cli/plugins/spcs/compute_pool/commands.py +241 -0
  191. snowflake/cli/plugins/spcs/compute_pool/manager.py +121 -0
  192. snowflake/cli/plugins/spcs/image_registry/__init__.py +13 -0
  193. snowflake/cli/plugins/spcs/image_registry/commands.py +65 -0
  194. snowflake/cli/plugins/spcs/image_registry/manager.py +105 -0
  195. snowflake/cli/plugins/spcs/image_repository/__init__.py +13 -0
  196. snowflake/cli/plugins/spcs/image_repository/commands.py +202 -0
  197. snowflake/cli/plugins/spcs/image_repository/manager.py +84 -0
  198. snowflake/cli/plugins/spcs/jobs/__init__.py +13 -0
  199. snowflake/cli/plugins/spcs/jobs/commands.py +78 -0
  200. snowflake/cli/plugins/spcs/jobs/manager.py +53 -0
  201. snowflake/cli/plugins/spcs/plugin_spec.py +30 -0
  202. snowflake/cli/plugins/spcs/services/__init__.py +13 -0
  203. snowflake/cli/plugins/spcs/services/commands.py +312 -0
  204. snowflake/cli/plugins/spcs/services/manager.py +170 -0
  205. snowflake/cli/plugins/sql/__init__.py +13 -0
  206. snowflake/cli/plugins/sql/commands.py +83 -0
  207. snowflake/cli/plugins/sql/manager.py +92 -0
  208. snowflake/cli/plugins/sql/plugin_spec.py +30 -0
  209. snowflake/cli/plugins/sql/snowsql_templating.py +28 -0
  210. snowflake/cli/plugins/stage/__init__.py +13 -0
  211. snowflake/cli/plugins/stage/commands.py +263 -0
  212. snowflake/cli/plugins/stage/diff.py +326 -0
  213. snowflake/cli/plugins/stage/manager.py +577 -0
  214. snowflake/cli/plugins/stage/md5.py +160 -0
  215. snowflake/cli/plugins/stage/plugin_spec.py +30 -0
  216. snowflake/cli/plugins/streamlit/__init__.py +13 -0
  217. snowflake/cli/plugins/streamlit/commands.py +179 -0
  218. snowflake/cli/plugins/streamlit/manager.py +222 -0
  219. snowflake/cli/plugins/streamlit/plugin_spec.py +30 -0
  220. snowflake/cli/plugins/workspace/__init__.py +13 -0
  221. snowflake/cli/plugins/workspace/commands.py +35 -0
  222. snowflake/cli/plugins/workspace/plugin_spec.py +30 -0
  223. snowflake/cli/templates/default_snowpark/.gitignore +4 -0
  224. snowflake/cli/templates/default_snowpark/app/__init__.py +0 -0
  225. snowflake/cli/templates/default_snowpark/app/common.py +2 -0
  226. snowflake/cli/templates/default_snowpark/app/functions.py +15 -0
  227. snowflake/cli/templates/default_snowpark/app/procedures.py +22 -0
  228. snowflake/cli/templates/default_snowpark/requirements.txt +1 -0
  229. snowflake/cli/templates/default_snowpark/snowflake.yml +23 -0
  230. snowflake/cli/templates/default_streamlit/.gitignore +4 -0
  231. snowflake/cli/templates/default_streamlit/common/hello.py +2 -0
  232. snowflake/cli/templates/default_streamlit/environment.yml +6 -0
  233. snowflake/cli/templates/default_streamlit/pages/my_page.py +3 -0
  234. snowflake/cli/templates/default_streamlit/snowflake.yml +10 -0
  235. snowflake/cli/templates/default_streamlit/streamlit_app.py +4 -0
  236. snowflake_cli-2.8.2.dist-info/METADATA +325 -0
  237. snowflake_cli-2.8.2.dist-info/RECORD +240 -0
  238. snowflake_cli-2.8.2.dist-info/WHEEL +4 -0
  239. snowflake_cli-2.8.2.dist-info/entry_points.txt +2 -0
  240. 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)