snowflake-cli-labs 2.8.0rc1__py3-none-any.whl → 3.0.0rc1__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 (224) hide show
  1. snowflake/cli/__about__.py +1 -1
  2. snowflake/cli/{app → _app}/__main__.py +1 -1
  3. snowflake/cli/{app → _app}/cli_app.py +12 -12
  4. snowflake/cli/{app → _app}/commands_registration/builtin_plugins.py +13 -19
  5. snowflake/cli/{app → _app}/commands_registration/command_plugins_loader.py +9 -9
  6. snowflake/cli/{app → _app}/commands_registration/commands_registration_with_callbacks.py +4 -4
  7. snowflake/cli/{app → _app}/commands_registration/exception_logging.py +2 -2
  8. snowflake/cli/{app → _app}/commands_registration/typer_registration.py +2 -2
  9. snowflake/cli/{app → _app}/dev/docs/commands_docs_generator.py +30 -12
  10. snowflake/cli/{app → _app}/dev/docs/generator.py +3 -3
  11. snowflake/cli/{app → _app}/dev/docs/project_definition_docs_generator.py +4 -4
  12. snowflake/cli/{app → _app}/dev/docs/templates/usage.rst.jinja2 +14 -4
  13. snowflake/cli/{app → _app}/main_typer.py +2 -2
  14. snowflake/cli/{app → _app}/printing.py +2 -2
  15. snowflake/cli/{app → _app}/snow_connector.py +24 -17
  16. snowflake/cli/{app → _app}/telemetry.py +4 -5
  17. snowflake/cli/{plugins → _plugins}/connection/commands.py +25 -7
  18. snowflake/cli/_plugins/connection/plugin_spec.py +30 -0
  19. snowflake/cli/{plugins → _plugins}/connection/util.py +16 -0
  20. snowflake/cli/{plugins → _plugins}/cortex/commands.py +54 -49
  21. snowflake/cli/{plugins → _plugins}/cortex/constants.py +1 -1
  22. snowflake/cli/{plugins → _plugins}/cortex/manager.py +5 -5
  23. snowflake/cli/{plugins → _plugins}/cortex/plugin_spec.py +1 -1
  24. snowflake/cli/{plugins → _plugins}/git/commands.py +32 -20
  25. snowflake/cli/{plugins → _plugins}/git/manager.py +20 -11
  26. snowflake/cli/{plugins → _plugins}/git/plugin_spec.py +1 -1
  27. snowflake/cli/{plugins → _plugins}/init/commands.py +10 -6
  28. snowflake/cli/{plugins → _plugins}/init/plugin_spec.py +1 -1
  29. snowflake/cli/{plugins → _plugins}/nativeapp/artifacts.py +14 -0
  30. snowflake/cli/_plugins/nativeapp/bundle_context.py +31 -0
  31. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/artifact_processor.py +3 -3
  32. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/compiler.py +32 -18
  33. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +249 -0
  34. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/setup/setup_driver.py.source +5 -2
  35. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/extension_function_utils.py +4 -4
  36. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/python_processor.py +23 -29
  37. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +93 -0
  38. snowflake/cli/{plugins → _plugins}/nativeapp/commands.py +171 -42
  39. snowflake/cli/{plugins → _plugins}/nativeapp/common_flags.py +1 -1
  40. snowflake/cli/{plugins → _plugins}/nativeapp/exceptions.py +3 -3
  41. snowflake/cli/{plugins → _plugins}/nativeapp/init.py +1 -1
  42. snowflake/cli/_plugins/nativeapp/manager.py +572 -0
  43. snowflake/cli/{plugins/connection → _plugins/nativeapp}/plugin_spec.py +1 -1
  44. snowflake/cli/{plugins → _plugins}/nativeapp/project_model.py +35 -19
  45. snowflake/cli/{plugins → _plugins}/nativeapp/run_processor.py +25 -23
  46. snowflake/cli/{plugins → _plugins}/nativeapp/teardown_processor.py +24 -110
  47. snowflake/cli/{plugins → _plugins}/nativeapp/v2_conversions/v2_to_v1_decorator.py +47 -28
  48. snowflake/cli/{plugins → _plugins}/nativeapp/version/commands.py +15 -12
  49. snowflake/cli/{plugins → _plugins}/nativeapp/version/version_processor.py +22 -20
  50. snowflake/cli/{plugins → _plugins}/notebook/commands.py +8 -6
  51. snowflake/cli/{plugins → _plugins}/notebook/manager.py +14 -14
  52. snowflake/cli/{plugins → _plugins}/notebook/plugin_spec.py +1 -1
  53. snowflake/cli/{plugins → _plugins}/notebook/types.py +0 -1
  54. snowflake/cli/{plugins → _plugins}/object/command_aliases.py +6 -5
  55. snowflake/cli/{plugins → _plugins}/object/commands.py +16 -10
  56. snowflake/cli/{plugins → _plugins}/object/manager.py +7 -6
  57. snowflake/cli/{plugins → _plugins}/object/plugin_spec.py +1 -1
  58. snowflake/cli/_plugins/snowpark/commands.py +450 -0
  59. snowflake/cli/_plugins/snowpark/common.py +268 -0
  60. snowflake/cli/{plugins → _plugins}/snowpark/models.py +0 -7
  61. snowflake/cli/{plugins → _plugins}/snowpark/package/anaconda_packages.py +2 -36
  62. snowflake/cli/{plugins → _plugins}/snowpark/package/commands.py +13 -74
  63. snowflake/cli/{plugins → _plugins}/snowpark/package/manager.py +4 -3
  64. snowflake/cli/{plugins → _plugins}/snowpark/package_utils.py +5 -5
  65. snowflake/cli/{plugins/nativeapp → _plugins/snowpark}/plugin_spec.py +1 -1
  66. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +109 -0
  67. snowflake/cli/{plugins → _plugins}/snowpark/snowpark_shared.py +0 -36
  68. snowflake/cli/{plugins → _plugins}/snowpark/zipper.py +16 -8
  69. snowflake/cli/{plugins → _plugins}/spcs/__init__.py +5 -7
  70. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/commands.py +29 -28
  71. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/manager.py +3 -3
  72. snowflake/cli/{plugins → _plugins}/spcs/image_registry/commands.py +3 -3
  73. snowflake/cli/{plugins → _plugins}/spcs/image_repository/commands.py +25 -19
  74. snowflake/cli/{plugins → _plugins}/spcs/image_repository/manager.py +1 -1
  75. snowflake/cli/{plugins → _plugins}/spcs/plugin_spec.py +1 -1
  76. snowflake/cli/{plugins → _plugins}/spcs/services/commands.py +66 -32
  77. snowflake/cli/{plugins → _plugins}/spcs/services/manager.py +43 -5
  78. snowflake/cli/{plugins → _plugins}/sql/commands.py +20 -17
  79. snowflake/cli/{plugins → _plugins}/sql/manager.py +1 -1
  80. snowflake/cli/{plugins → _plugins}/sql/plugin_spec.py +1 -1
  81. snowflake/cli/{plugins → _plugins}/stage/commands.py +20 -17
  82. snowflake/cli/{plugins → _plugins}/stage/diff.py +1 -47
  83. snowflake/cli/{plugins → _plugins}/stage/manager.py +54 -21
  84. snowflake/cli/{plugins → _plugins}/stage/plugin_spec.py +1 -1
  85. snowflake/cli/_plugins/stage/utils.py +54 -0
  86. snowflake/cli/{plugins → _plugins}/streamlit/commands.py +59 -62
  87. snowflake/cli/{plugins → _plugins}/streamlit/manager.py +51 -70
  88. snowflake/cli/_plugins/streamlit/plugin_spec.py +30 -0
  89. snowflake/cli/_plugins/workspace/action_context.py +17 -0
  90. snowflake/cli/_plugins/workspace/commands.py +194 -0
  91. snowflake/cli/_plugins/workspace/manager.py +73 -0
  92. snowflake/cli/{plugins → _plugins}/workspace/plugin_spec.py +1 -1
  93. snowflake/cli/api/cli_global_context.py +40 -13
  94. snowflake/cli/api/commands/common.py +25 -0
  95. snowflake/cli/api/commands/decorators.py +5 -4
  96. snowflake/cli/api/commands/experimental_behaviour.py +2 -3
  97. snowflake/cli/api/commands/flags.py +97 -179
  98. snowflake/cli/api/commands/overrideable_parameter.py +143 -0
  99. snowflake/cli/api/commands/snow_typer.py +14 -6
  100. snowflake/cli/api/commands/typer_pre_execute.py +3 -3
  101. snowflake/cli/api/commands/utils.py +18 -0
  102. snowflake/cli/api/config.py +18 -5
  103. snowflake/cli/api/console/abc.py +5 -2
  104. snowflake/cli/api/constants.py +11 -0
  105. snowflake/cli/api/entities/application_entity.py +12 -0
  106. snowflake/cli/api/entities/application_package_entity.py +553 -0
  107. snowflake/cli/api/entities/common.py +51 -0
  108. snowflake/cli/api/entities/snowpark_entity.py +29 -0
  109. snowflake/cli/api/entities/streamlit_entity.py +12 -0
  110. snowflake/cli/api/entities/utils.py +357 -0
  111. snowflake/cli/api/exceptions.py +31 -5
  112. snowflake/cli/api/feature_flags.py +0 -1
  113. snowflake/cli/api/identifiers.py +41 -9
  114. snowflake/cli/api/project/definition.py +37 -6
  115. snowflake/cli/api/project/definition_conversion.py +194 -0
  116. snowflake/cli/api/project/definition_manager.py +12 -1
  117. snowflake/cli/api/project/project_verification.py +3 -3
  118. snowflake/cli/api/project/schemas/entities/{application_entity.py → application_entity_model.py} +21 -9
  119. snowflake/cli/api/project/schemas/entities/{application_package_entity.py → application_package_entity_model.py} +43 -15
  120. snowflake/cli/api/project/schemas/entities/common.py +80 -6
  121. snowflake/cli/api/project/schemas/entities/entities.py +38 -8
  122. snowflake/cli/api/project/schemas/entities/snowpark_entity.py +176 -0
  123. snowflake/cli/api/project/schemas/entities/streamlit_entity_model.py +73 -0
  124. snowflake/cli/api/project/schemas/identifier_model.py +10 -1
  125. snowflake/cli/api/project/schemas/native_app/application.py +8 -9
  126. snowflake/cli/api/project/schemas/native_app/package.py +7 -1
  127. snowflake/cli/api/project/schemas/project_definition.py +98 -27
  128. snowflake/cli/api/project/schemas/updatable_model.py +11 -3
  129. snowflake/cli/api/project/util.py +23 -6
  130. snowflake/cli/api/rendering/jinja.py +14 -8
  131. snowflake/cli/api/rendering/project_definition_templates.py +1 -1
  132. snowflake/cli/api/rendering/sql_templates.py +43 -11
  133. snowflake/cli/api/secure_path.py +16 -18
  134. snowflake/cli/api/secure_utils.py +90 -1
  135. snowflake/cli/api/sql_execution.py +48 -19
  136. snowflake/cli/api/utils/definition_rendering.py +18 -8
  137. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0rc1.dist-info}/METADATA +13 -13
  138. snowflake_cli_labs-3.0.0rc1.dist-info/RECORD +236 -0
  139. snowflake_cli_labs-3.0.0rc1.dist-info/entry_points.txt +2 -0
  140. snowflake/cli/api/commands/project_initialisation.py +0 -65
  141. snowflake/cli/app/build_and_push.sh +0 -8
  142. snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -172
  143. snowflake/cli/plugins/nativeapp/manager.py +0 -823
  144. snowflake/cli/plugins/object_stage_deprecated/__init__.py +0 -15
  145. snowflake/cli/plugins/object_stage_deprecated/commands.py +0 -122
  146. snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +0 -32
  147. snowflake/cli/plugins/snowpark/commands.py +0 -548
  148. snowflake/cli/plugins/snowpark/common.py +0 -307
  149. snowflake/cli/plugins/snowpark/manager.py +0 -109
  150. snowflake/cli/plugins/snowpark/plugin_spec.py +0 -30
  151. snowflake/cli/plugins/snowpark/snowpark_package_paths.py +0 -65
  152. snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
  153. snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
  154. snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
  155. snowflake/cli/plugins/workspace/commands.py +0 -35
  156. snowflake/cli/templates/default_snowpark/.gitignore +0 -4
  157. snowflake/cli/templates/default_snowpark/app/__init__.py +0 -0
  158. snowflake/cli/templates/default_snowpark/app/common.py +0 -2
  159. snowflake/cli/templates/default_snowpark/app/functions.py +0 -15
  160. snowflake/cli/templates/default_snowpark/app/procedures.py +0 -22
  161. snowflake/cli/templates/default_snowpark/requirements.txt +0 -1
  162. snowflake/cli/templates/default_snowpark/snowflake.yml +0 -23
  163. snowflake/cli/templates/default_streamlit/.gitignore +0 -4
  164. snowflake/cli/templates/default_streamlit/common/hello.py +0 -2
  165. snowflake/cli/templates/default_streamlit/environment.yml +0 -6
  166. snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -3
  167. snowflake/cli/templates/default_streamlit/snowflake.yml +0 -10
  168. snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -4
  169. snowflake_cli_labs-2.8.0rc1.dist-info/RECORD +0 -240
  170. snowflake_cli_labs-2.8.0rc1.dist-info/entry_points.txt +0 -2
  171. /snowflake/cli/{app → _app}/__init__.py +0 -0
  172. /snowflake/cli/{app → _app}/api_impl/__init__.py +0 -0
  173. /snowflake/cli/{app → _app}/api_impl/plugin/__init__.py +0 -0
  174. /snowflake/cli/{app → _app}/api_impl/plugin/plugin_config_provider_impl.py +0 -0
  175. /snowflake/cli/{app → _app}/commands_registration/__init__.py +0 -0
  176. /snowflake/cli/{app → _app}/commands_registration/threadsafe.py +0 -0
  177. /snowflake/cli/{app → _app}/constants.py +0 -0
  178. /snowflake/cli/{app → _app}/dev/__init__.py +0 -0
  179. /snowflake/cli/{app → _app}/dev/commands_structure.py +0 -0
  180. /snowflake/cli/{app → _app}/dev/docs/__init__.py +0 -0
  181. /snowflake/cli/{app → _app}/dev/docs/project_definition_generate_json_schema.py +0 -0
  182. /snowflake/cli/{app → _app}/dev/docs/template_utils.py +0 -0
  183. /snowflake/cli/{app → _app}/dev/docs/templates/definition_description.rst.jinja2 +0 -0
  184. /snowflake/cli/{app → _app}/dev/docs/templates/overview.rst.jinja2 +0 -0
  185. /snowflake/cli/{app → _app}/dev/pycharm_remote_debug.py +0 -0
  186. /snowflake/cli/{app → _app}/loggers.py +0 -0
  187. /snowflake/cli/{plugins → _plugins}/__init__.py +0 -0
  188. /snowflake/cli/{plugins → _plugins}/connection/__init__.py +0 -0
  189. /snowflake/cli/{plugins → _plugins}/cortex/__init__.py +0 -0
  190. /snowflake/cli/{plugins → _plugins}/cortex/types.py +0 -0
  191. /snowflake/cli/{plugins → _plugins}/git/__init__.py +0 -0
  192. /snowflake/cli/{plugins → _plugins}/init/__init__.py +0 -0
  193. /snowflake/cli/{plugins → _plugins}/nativeapp/__init__.py +0 -0
  194. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/__init__.py +0 -0
  195. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/sandbox.py +0 -0
  196. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -0
  197. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/models.py +0 -0
  198. /snowflake/cli/{plugins → _plugins}/nativeapp/constants.py +0 -0
  199. /snowflake/cli/{plugins → _plugins}/nativeapp/feature_flags.py +0 -0
  200. /snowflake/cli/{plugins → _plugins}/nativeapp/policy.py +0 -0
  201. /snowflake/cli/{plugins → _plugins}/nativeapp/utils.py +0 -0
  202. /snowflake/cli/{plugins → _plugins}/nativeapp/version/__init__.py +0 -0
  203. /snowflake/cli/{plugins → _plugins}/notebook/__init__.py +0 -0
  204. /snowflake/cli/{plugins → _plugins}/notebook/exceptions.py +0 -0
  205. /snowflake/cli/{plugins → _plugins}/object/__init__.py +0 -0
  206. /snowflake/cli/{plugins → _plugins}/object/common.py +0 -0
  207. /snowflake/cli/{plugins → _plugins}/snowpark/__init__.py +0 -0
  208. /snowflake/cli/{plugins → _plugins}/snowpark/package/__init__.py +0 -0
  209. /snowflake/cli/{plugins → _plugins}/snowpark/package/utils.py +0 -0
  210. /snowflake/cli/{plugins → _plugins}/spcs/common.py +0 -0
  211. /snowflake/cli/{plugins → _plugins}/spcs/compute_pool/__init__.py +0 -0
  212. /snowflake/cli/{plugins → _plugins}/spcs/image_registry/__init__.py +0 -0
  213. /snowflake/cli/{plugins → _plugins}/spcs/image_registry/manager.py +0 -0
  214. /snowflake/cli/{plugins → _plugins}/spcs/image_repository/__init__.py +0 -0
  215. /snowflake/cli/{plugins/spcs/jobs → _plugins/spcs/services}/__init__.py +0 -0
  216. /snowflake/cli/{plugins/spcs/services → _plugins/sql}/__init__.py +0 -0
  217. /snowflake/cli/{plugins → _plugins}/sql/snowsql_templating.py +0 -0
  218. /snowflake/cli/{plugins/sql → _plugins/stage}/__init__.py +0 -0
  219. /snowflake/cli/{plugins → _plugins}/stage/md5.py +0 -0
  220. /snowflake/cli/{plugins/stage → _plugins/streamlit}/__init__.py +0 -0
  221. /snowflake/cli/{plugins/streamlit → _plugins/workspace}/__init__.py +0 -0
  222. /snowflake/cli/{plugins/workspace → api/project/schemas/entities}/__init__.py +0 -0
  223. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0rc1.dist-info}/WHEEL +0 -0
  224. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0rc1.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, List, Optional, Tuple
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 cli_context_manager
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: cli_context_manager.connection_context.set_connection_name
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
- autocompletion=lambda: list(get_all_connections()),
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: cli_context_manager.connection_context.set_temporary_connection
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(lambda: cli_context_manager.connection_context.set_account),
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: cli_context_manager.connection_context.set_user),
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: cli_context_manager.connection_context.set_password)(value)
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: cli_context_manager.connection_context.set_authenticator
129
+ lambda: get_cli_context_manager().connection_context.set_authenticator
229
130
  ),
230
131
  show_default=False,
231
132
  rich_help_panel=_CONNECTION_SECTION,
@@ -233,11 +134,12 @@ AuthenticatorOption = typer.Option(
233
134
 
234
135
  PrivateKeyPathOption = typer.Option(
235
136
  None,
137
+ "--private-key-file",
236
138
  "--private-key-path",
237
- help="Snowflake private key path. Overrides the value specified for the connection.",
139
+ help="Snowflake private key file path. Overrides the value specified for the connection.",
238
140
  hide_input=True,
239
141
  callback=_callback(
240
- lambda: cli_context_manager.connection_context.set_private_key_path
142
+ lambda: get_cli_context_manager().connection_context.set_private_key_file
241
143
  ),
242
144
  show_default=False,
243
145
  rich_help_panel=_CONNECTION_SECTION,
@@ -252,7 +154,7 @@ SessionTokenOption = typer.Option(
252
154
  help="Snowflake session token. Can be used only in conjunction with --master-token. Overrides the value specified for the connection.",
253
155
  hide_input=True,
254
156
  callback=_callback(
255
- lambda: cli_context_manager.connection_context.set_session_token
157
+ lambda: get_cli_context_manager().connection_context.set_session_token
256
158
  ),
257
159
  show_default=False,
258
160
  rich_help_panel=_CONNECTION_SECTION,
@@ -267,7 +169,9 @@ MasterTokenOption = typer.Option(
267
169
  "--master-token",
268
170
  help="Snowflake master token. Can be used only in conjunction with --session-token. Overrides the value specified for the connection.",
269
171
  hide_input=True,
270
- callback=_callback(lambda: cli_context_manager.connection_context.set_master_token),
172
+ callback=_callback(
173
+ lambda: get_cli_context_manager().connection_context.set_master_token
174
+ ),
271
175
  show_default=False,
272
176
  rich_help_panel=_CONNECTION_SECTION,
273
177
  exists=True,
@@ -281,7 +185,7 @@ TokenFilePathOption = typer.Option(
281
185
  "--token-file-path",
282
186
  help="Path to file with an OAuth token that should be used when connecting to Snowflake",
283
187
  callback=_callback(
284
- lambda: cli_context_manager.connection_context.set_token_file_path
188
+ lambda: get_cli_context_manager().connection_context.set_token_file_path
285
189
  ),
286
190
  show_default=False,
287
191
  rich_help_panel=_CONNECTION_SECTION,
@@ -295,7 +199,9 @@ DatabaseOption = typer.Option(
295
199
  "--database",
296
200
  "--dbname",
297
201
  help="Database to use. Overrides the value specified for the connection.",
298
- callback=_callback(lambda: cli_context_manager.connection_context.set_database),
202
+ callback=_callback(
203
+ lambda: get_cli_context_manager().connection_context.set_database
204
+ ),
299
205
  show_default=False,
300
206
  rich_help_panel=_CONNECTION_SECTION,
301
207
  )
@@ -305,7 +211,7 @@ SchemaOption = typer.Option(
305
211
  "--schema",
306
212
  "--schemaname",
307
213
  help="Database schema to use. Overrides the value specified for the connection.",
308
- callback=_callback(lambda: cli_context_manager.connection_context.set_schema),
214
+ callback=_callback(lambda: get_cli_context_manager().connection_context.set_schema),
309
215
  show_default=False,
310
216
  rich_help_panel=_CONNECTION_SECTION,
311
217
  )
@@ -315,7 +221,7 @@ RoleOption = typer.Option(
315
221
  "--role",
316
222
  "--rolename",
317
223
  help="Role to use. Overrides the value specified for the connection.",
318
- callback=_callback(lambda: cli_context_manager.connection_context.set_role),
224
+ callback=_callback(lambda: get_cli_context_manager().connection_context.set_role),
319
225
  show_default=False,
320
226
  rich_help_panel=_CONNECTION_SECTION,
321
227
  )
@@ -324,7 +230,9 @@ WarehouseOption = typer.Option(
324
230
  None,
325
231
  "--warehouse",
326
232
  help="Warehouse to use. Overrides the value specified for the connection.",
327
- callback=_callback(lambda: cli_context_manager.connection_context.set_warehouse),
233
+ callback=_callback(
234
+ lambda: get_cli_context_manager().connection_context.set_warehouse
235
+ ),
328
236
  show_default=False,
329
237
  rich_help_panel=_CONNECTION_SECTION,
330
238
  )
@@ -333,7 +241,9 @@ MfaPasscodeOption = typer.Option(
333
241
  None,
334
242
  "--mfa-passcode",
335
243
  help="Token to use for multi-factor authentication (MFA)",
336
- callback=_callback(lambda: cli_context_manager.connection_context.set_mfa_passcode),
244
+ callback=_callback(
245
+ lambda: get_cli_context_manager().connection_context.set_mfa_passcode
246
+ ),
337
247
  prompt="MFA passcode",
338
248
  prompt_required=False,
339
249
  show_default=False,
@@ -344,18 +254,31 @@ EnableDiagOption = typer.Option(
344
254
  False,
345
255
  "--enable-diag",
346
256
  help="Run python connector diagnostic test",
347
- callback=_callback(lambda: cli_context_manager.connection_context.set_enable_diag),
257
+ callback=_callback(
258
+ lambda: get_cli_context_manager().connection_context.set_enable_diag
259
+ ),
348
260
  show_default=False,
349
261
  is_flag=True,
350
262
  rich_help_panel=_CONNECTION_SECTION,
351
263
  )
352
264
 
265
+ # Set default via callback to avoid including tempdir path in generated docs (snow --docs).
266
+ # Use constant instead of None, as None is removed from telemetry data.
267
+ _DIAG_LOG_DEFAULT_VALUE = "<temporary_directory>"
268
+
269
+
270
+ def _diag_log_path_callback(path: str):
271
+ if path != _DIAG_LOG_DEFAULT_VALUE:
272
+ return path
273
+ return tempfile.gettempdir()
274
+
275
+
353
276
  DiagLogPathOption: Path = typer.Option(
354
- tempfile.gettempdir(),
277
+ _DIAG_LOG_DEFAULT_VALUE,
355
278
  "--diag-log-path",
356
279
  help="Diagnostic report path",
357
280
  callback=_callback(
358
- lambda: cli_context_manager.connection_context.set_diag_log_path
281
+ lambda: get_cli_context_manager().connection_context.set_diag_log_path
359
282
  ),
360
283
  show_default=False,
361
284
  rich_help_panel=_CONNECTION_SECTION,
@@ -368,7 +291,7 @@ DiagAllowlistPathOption: Path = typer.Option(
368
291
  "--diag-allowlist-path",
369
292
  help="Diagnostic report path to optional allowlist",
370
293
  callback=_callback(
371
- lambda: cli_context_manager.connection_context.set_diag_allowlist_path
294
+ lambda: get_cli_context_manager().connection_context.set_diag_allowlist_path
372
295
  ),
373
296
  show_default=False,
374
297
  rich_help_panel=_CONNECTION_SECTION,
@@ -381,7 +304,7 @@ OutputFormatOption = typer.Option(
381
304
  "--format",
382
305
  help="Specifies the output format.",
383
306
  case_sensitive=False,
384
- callback=_callback(lambda: cli_context_manager.set_output_format),
307
+ callback=_callback(lambda: get_cli_context_manager().set_output_format),
385
308
  rich_help_panel=_CLI_BEHAVIOUR,
386
309
  )
387
310
 
@@ -389,7 +312,7 @@ SilentOption = typer.Option(
389
312
  False,
390
313
  "--silent",
391
314
  help="Turns off intermediate output to console.",
392
- callback=_callback(lambda: cli_context_manager.set_silent),
315
+ callback=_callback(lambda: get_cli_context_manager().set_silent),
393
316
  is_flag=True,
394
317
  rich_help_panel=_CLI_BEHAVIOUR,
395
318
  is_eager=True,
@@ -400,7 +323,7 @@ VerboseOption = typer.Option(
400
323
  "--verbose",
401
324
  "-v",
402
325
  help="Displays log entries for log levels `info` and higher.",
403
- callback=_callback(lambda: cli_context_manager.set_verbose),
326
+ callback=_callback(lambda: get_cli_context_manager().set_verbose),
404
327
  is_flag=True,
405
328
  rich_help_panel=_CLI_BEHAVIOUR,
406
329
  )
@@ -409,7 +332,7 @@ DebugOption = typer.Option(
409
332
  False,
410
333
  "--debug",
411
334
  help="Displays log entries for log levels `debug` and higher; debug logs contains additional information.",
412
- callback=_callback(lambda: cli_context_manager.set_enable_tracebacks),
335
+ callback=_callback(lambda: get_cli_context_manager().set_enable_tracebacks),
413
336
  is_flag=True,
414
337
  rich_help_panel=_CLI_BEHAVIOUR,
415
338
  )
@@ -450,6 +373,10 @@ OnErrorOption = typer.Option(
450
373
  NoInteractiveOption = typer.Option(False, "--no-interactive", help="Disable prompting.")
451
374
 
452
375
 
376
+ def entity_argument(entity_type: str) -> typer.Argument:
377
+ return typer.Argument(None, help=f"ID of {entity_type} entity.")
378
+
379
+
453
380
  def variables_option(description: str):
454
381
  return typer.Option(
455
382
  None,
@@ -508,17 +435,46 @@ def experimental_option(
508
435
  "--experimental",
509
436
  help=help_text,
510
437
  hidden=True,
511
- callback=_callback(lambda: cli_context_manager.set_experimental),
438
+ callback=_callback(lambda: get_cli_context_manager().set_experimental),
512
439
  is_flag=True,
513
440
  rich_help_panel=_CLI_BEHAVIOUR,
514
441
  )
515
442
 
516
443
 
517
- def identifier_argument(sf_object: str, example: str) -> typer.Argument:
444
+ class IdentifierType(click.ParamType):
445
+ name = "TEXT"
446
+
447
+ def convert(self, value, param, ctx):
448
+ return FQN.from_string(value)
449
+
450
+
451
+ class IdentifierStageType(click.ParamType):
452
+ name = "TEXT"
453
+
454
+ def convert(self, value, param, ctx):
455
+ return FQN.from_stage(value)
456
+
457
+
458
+ def identifier_argument(
459
+ sf_object: str,
460
+ example: str,
461
+ click_type: click.ParamType = IdentifierType(),
462
+ callback: Callable | None = None,
463
+ ) -> typer.Argument:
518
464
  return typer.Argument(
519
465
  ...,
520
466
  help=f"Identifier of the {sf_object}. For example: {example}",
521
467
  show_default=False,
468
+ click_type=click_type,
469
+ callback=callback,
470
+ )
471
+
472
+
473
+ def identifier_stage_argument(
474
+ sf_object: str, example: str, callback: Callable | None = None
475
+ ) -> typer.Argument:
476
+ return identifier_argument(
477
+ sf_object, example, click_type=IdentifierStageType(), callback=callback
522
478
  )
523
479
 
524
480
 
@@ -531,6 +487,7 @@ def execution_identifier_argument(sf_object: str, example: str) -> typer.Argumen
531
487
 
532
488
 
533
489
  def register_project_definition(is_optional: bool) -> None:
490
+ cli_context_manager = get_cli_context_manager()
534
491
  project_path = cli_context_manager.project_path_arg
535
492
  env_overrides_args = cli_context_manager.project_env_overrides_args
536
493
 
@@ -551,7 +508,7 @@ def register_project_definition(is_optional: bool) -> None:
551
508
 
552
509
  def project_definition_option(is_optional: bool):
553
510
  def project_definition_callback(project_path: str) -> None:
554
- cli_context_manager.set_project_path_arg(project_path)
511
+ get_cli_context_manager().set_project_path_arg(project_path)
555
512
  register_pre_execute_command(lambda: register_project_definition(is_optional))
556
513
 
557
514
  return typer.Option(
@@ -570,30 +527,17 @@ def project_env_overrides_option():
570
527
  env_overrides_args_map = {
571
528
  v.key: v.value for v in parse_key_value_variables(env_overrides_args_list)
572
529
  }
573
- cli_context_manager.set_project_env_overrides_args(env_overrides_args_map)
530
+ get_cli_context_manager().set_project_env_overrides_args(env_overrides_args_map)
574
531
 
575
532
  return typer.Option(
576
533
  [],
577
534
  "--env",
578
- help="String in format of key=value. Overrides variables from env section used for templating.",
535
+ help="String in format of key=value. Overrides variables from env section used for templates.",
579
536
  callback=_callback(lambda: project_env_overrides_callback),
580
537
  show_default=False,
581
538
  )
582
539
 
583
540
 
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
541
  def deprecated_flag_callback(msg: str):
598
542
  def _warning_callback(ctx: click.Context, param: click.Parameter, value: Any):
599
543
  if ctx.get_parameter_source(param.name) != click.core.ParameterSource.DEFAULT: # type: ignore[attr-defined]
@@ -612,29 +556,3 @@ def deprecated_flag_callback_enum(msg: str):
612
556
  return value.value
613
557
 
614
558
  return _warning_callback
615
-
616
-
617
- @dataclass
618
- class Variable:
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}'")
637
-
638
- key, value = p.split("=", 1)
639
- result.append(Variable(key.strip(), value.strip()))
640
- return result
@@ -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)