snowflake-cli-labs 3.0.0rc4__py3-none-any.whl → 3.0.1__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 (244) hide show
  1. README.md +21 -0
  2. {snowflake_cli_labs-3.0.0rc4.dist-info → snowflake_cli_labs-3.0.1.dist-info}/METADATA +6 -96
  3. snowflake_cli_labs-3.0.1.dist-info/RECORD +5 -0
  4. snowflake/cli/__about__.py +0 -17
  5. snowflake/cli/__init__.py +0 -13
  6. snowflake/cli/_app/__init__.py +0 -22
  7. snowflake/cli/_app/__main__.py +0 -31
  8. snowflake/cli/_app/api_impl/__init__.py +0 -13
  9. snowflake/cli/_app/api_impl/plugin/__init__.py +0 -13
  10. snowflake/cli/_app/api_impl/plugin/plugin_config_provider_impl.py +0 -66
  11. snowflake/cli/_app/cli_app.py +0 -252
  12. snowflake/cli/_app/commands_registration/__init__.py +0 -33
  13. snowflake/cli/_app/commands_registration/builtin_plugins.py +0 -50
  14. snowflake/cli/_app/commands_registration/command_plugins_loader.py +0 -169
  15. snowflake/cli/_app/commands_registration/commands_registration_with_callbacks.py +0 -105
  16. snowflake/cli/_app/commands_registration/exception_logging.py +0 -26
  17. snowflake/cli/_app/commands_registration/threadsafe.py +0 -48
  18. snowflake/cli/_app/commands_registration/typer_registration.py +0 -153
  19. snowflake/cli/_app/constants.py +0 -19
  20. snowflake/cli/_app/dev/__init__.py +0 -13
  21. snowflake/cli/_app/dev/commands_structure.py +0 -48
  22. snowflake/cli/_app/dev/docs/__init__.py +0 -13
  23. snowflake/cli/_app/dev/docs/commands_docs_generator.py +0 -118
  24. snowflake/cli/_app/dev/docs/generator.py +0 -35
  25. snowflake/cli/_app/dev/docs/project_definition_docs_generator.py +0 -58
  26. snowflake/cli/_app/dev/docs/project_definition_generate_json_schema.py +0 -227
  27. snowflake/cli/_app/dev/docs/template_utils.py +0 -23
  28. snowflake/cli/_app/dev/docs/templates/definition_description.rst.jinja2 +0 -38
  29. snowflake/cli/_app/dev/docs/templates/overview.rst.jinja2 +0 -9
  30. snowflake/cli/_app/dev/docs/templates/usage.rst.jinja2 +0 -67
  31. snowflake/cli/_app/dev/pycharm_remote_debug.py +0 -46
  32. snowflake/cli/_app/loggers.py +0 -199
  33. snowflake/cli/_app/main_typer.py +0 -62
  34. snowflake/cli/_app/printing.py +0 -181
  35. snowflake/cli/_app/secret.py +0 -9
  36. snowflake/cli/_app/snow_connector.py +0 -309
  37. snowflake/cli/_app/telemetry.py +0 -220
  38. snowflake/cli/_app/version_check.py +0 -74
  39. snowflake/cli/_plugins/__init__.py +0 -13
  40. snowflake/cli/_plugins/connection/__init__.py +0 -13
  41. snowflake/cli/_plugins/connection/commands.py +0 -353
  42. snowflake/cli/_plugins/connection/plugin_spec.py +0 -30
  43. snowflake/cli/_plugins/connection/util.py +0 -195
  44. snowflake/cli/_plugins/cortex/__init__.py +0 -13
  45. snowflake/cli/_plugins/cortex/commands.py +0 -332
  46. snowflake/cli/_plugins/cortex/constants.py +0 -17
  47. snowflake/cli/_plugins/cortex/manager.py +0 -189
  48. snowflake/cli/_plugins/cortex/plugin_spec.py +0 -30
  49. snowflake/cli/_plugins/cortex/types.py +0 -22
  50. snowflake/cli/_plugins/git/__init__.py +0 -13
  51. snowflake/cli/_plugins/git/commands.py +0 -358
  52. snowflake/cli/_plugins/git/manager.py +0 -151
  53. snowflake/cli/_plugins/git/plugin_spec.py +0 -30
  54. snowflake/cli/_plugins/helpers/__init__.py +0 -13
  55. snowflake/cli/_plugins/helpers/commands.py +0 -61
  56. snowflake/cli/_plugins/helpers/plugin_spec.py +0 -30
  57. snowflake/cli/_plugins/init/__init__.py +0 -13
  58. snowflake/cli/_plugins/init/commands.py +0 -248
  59. snowflake/cli/_plugins/init/plugin_spec.py +0 -30
  60. snowflake/cli/_plugins/nativeapp/__init__.py +0 -13
  61. snowflake/cli/_plugins/nativeapp/artifacts.py +0 -757
  62. snowflake/cli/_plugins/nativeapp/bundle_context.py +0 -31
  63. snowflake/cli/_plugins/nativeapp/codegen/__init__.py +0 -13
  64. snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +0 -91
  65. snowflake/cli/_plugins/nativeapp/codegen/compiler.py +0 -149
  66. snowflake/cli/_plugins/nativeapp/codegen/sandbox.py +0 -306
  67. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -249
  68. snowflake/cli/_plugins/nativeapp/codegen/setup/setup_driver.py.source +0 -59
  69. snowflake/cli/_plugins/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -181
  70. snowflake/cli/_plugins/nativeapp/codegen/snowpark/extension_function_utils.py +0 -217
  71. snowflake/cli/_plugins/nativeapp/codegen/snowpark/models.py +0 -61
  72. snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +0 -523
  73. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +0 -114
  74. snowflake/cli/_plugins/nativeapp/commands.py +0 -559
  75. snowflake/cli/_plugins/nativeapp/common_flags.py +0 -44
  76. snowflake/cli/_plugins/nativeapp/constants.py +0 -27
  77. snowflake/cli/_plugins/nativeapp/entities/__init__.py +0 -0
  78. snowflake/cli/_plugins/nativeapp/entities/application.py +0 -878
  79. snowflake/cli/_plugins/nativeapp/entities/application_package.py +0 -1392
  80. snowflake/cli/_plugins/nativeapp/exceptions.py +0 -113
  81. snowflake/cli/_plugins/nativeapp/feature_flags.py +0 -24
  82. snowflake/cli/_plugins/nativeapp/manager.py +0 -415
  83. snowflake/cli/_plugins/nativeapp/plugin_spec.py +0 -30
  84. snowflake/cli/_plugins/nativeapp/policy.py +0 -53
  85. snowflake/cli/_plugins/nativeapp/project_model.py +0 -211
  86. snowflake/cli/_plugins/nativeapp/run_processor.py +0 -184
  87. snowflake/cli/_plugins/nativeapp/same_account_install_method.py +0 -70
  88. snowflake/cli/_plugins/nativeapp/teardown_processor.py +0 -70
  89. snowflake/cli/_plugins/nativeapp/utils.py +0 -98
  90. snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +0 -262
  91. snowflake/cli/_plugins/nativeapp/version/__init__.py +0 -13
  92. snowflake/cli/_plugins/nativeapp/version/commands.py +0 -141
  93. snowflake/cli/_plugins/nativeapp/version/version_processor.py +0 -98
  94. snowflake/cli/_plugins/notebook/__init__.py +0 -13
  95. snowflake/cli/_plugins/notebook/commands.py +0 -86
  96. snowflake/cli/_plugins/notebook/exceptions.py +0 -20
  97. snowflake/cli/_plugins/notebook/manager.py +0 -71
  98. snowflake/cli/_plugins/notebook/plugin_spec.py +0 -30
  99. snowflake/cli/_plugins/notebook/types.py +0 -15
  100. snowflake/cli/_plugins/object/__init__.py +0 -13
  101. snowflake/cli/_plugins/object/command_aliases.py +0 -95
  102. snowflake/cli/_plugins/object/commands.py +0 -180
  103. snowflake/cli/_plugins/object/common.py +0 -85
  104. snowflake/cli/_plugins/object/manager.py +0 -118
  105. snowflake/cli/_plugins/object/plugin_spec.py +0 -30
  106. snowflake/cli/_plugins/snowpark/__init__.py +0 -13
  107. snowflake/cli/_plugins/snowpark/commands.py +0 -450
  108. snowflake/cli/_plugins/snowpark/common.py +0 -268
  109. snowflake/cli/_plugins/snowpark/models.py +0 -150
  110. snowflake/cli/_plugins/snowpark/package/__init__.py +0 -13
  111. snowflake/cli/_plugins/snowpark/package/anaconda_packages.py +0 -199
  112. snowflake/cli/_plugins/snowpark/package/commands.py +0 -195
  113. snowflake/cli/_plugins/snowpark/package/manager.py +0 -44
  114. snowflake/cli/_plugins/snowpark/package/utils.py +0 -26
  115. snowflake/cli/_plugins/snowpark/package_utils.py +0 -354
  116. snowflake/cli/_plugins/snowpark/plugin_spec.py +0 -30
  117. snowflake/cli/_plugins/snowpark/snowpark_entity.py +0 -29
  118. snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +0 -173
  119. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +0 -109
  120. snowflake/cli/_plugins/snowpark/snowpark_shared.py +0 -59
  121. snowflake/cli/_plugins/snowpark/zipper.py +0 -89
  122. snowflake/cli/_plugins/spcs/__init__.py +0 -33
  123. snowflake/cli/_plugins/spcs/common.py +0 -99
  124. snowflake/cli/_plugins/spcs/compute_pool/__init__.py +0 -13
  125. snowflake/cli/_plugins/spcs/compute_pool/commands.py +0 -241
  126. snowflake/cli/_plugins/spcs/compute_pool/manager.py +0 -121
  127. snowflake/cli/_plugins/spcs/image_registry/__init__.py +0 -13
  128. snowflake/cli/_plugins/spcs/image_registry/commands.py +0 -65
  129. snowflake/cli/_plugins/spcs/image_registry/manager.py +0 -105
  130. snowflake/cli/_plugins/spcs/image_repository/__init__.py +0 -13
  131. snowflake/cli/_plugins/spcs/image_repository/commands.py +0 -202
  132. snowflake/cli/_plugins/spcs/image_repository/manager.py +0 -84
  133. snowflake/cli/_plugins/spcs/plugin_spec.py +0 -30
  134. snowflake/cli/_plugins/spcs/services/__init__.py +0 -13
  135. snowflake/cli/_plugins/spcs/services/commands.py +0 -345
  136. snowflake/cli/_plugins/spcs/services/manager.py +0 -208
  137. snowflake/cli/_plugins/sql/__init__.py +0 -13
  138. snowflake/cli/_plugins/sql/commands.py +0 -86
  139. snowflake/cli/_plugins/sql/manager.py +0 -92
  140. snowflake/cli/_plugins/sql/plugin_spec.py +0 -30
  141. snowflake/cli/_plugins/sql/snowsql_templating.py +0 -28
  142. snowflake/cli/_plugins/stage/__init__.py +0 -13
  143. snowflake/cli/_plugins/stage/commands.py +0 -264
  144. snowflake/cli/_plugins/stage/diff.py +0 -280
  145. snowflake/cli/_plugins/stage/manager.py +0 -582
  146. snowflake/cli/_plugins/stage/md5.py +0 -160
  147. snowflake/cli/_plugins/stage/plugin_spec.py +0 -30
  148. snowflake/cli/_plugins/stage/utils.py +0 -54
  149. snowflake/cli/_plugins/streamlit/__init__.py +0 -13
  150. snowflake/cli/_plugins/streamlit/commands.py +0 -195
  151. snowflake/cli/_plugins/streamlit/manager.py +0 -220
  152. snowflake/cli/_plugins/streamlit/plugin_spec.py +0 -30
  153. snowflake/cli/_plugins/streamlit/streamlit_entity.py +0 -12
  154. snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +0 -66
  155. snowflake/cli/_plugins/workspace/__init__.py +0 -13
  156. snowflake/cli/_plugins/workspace/action_context.py +0 -18
  157. snowflake/cli/_plugins/workspace/commands.py +0 -306
  158. snowflake/cli/_plugins/workspace/manager.py +0 -74
  159. snowflake/cli/_plugins/workspace/plugin_spec.py +0 -30
  160. snowflake/cli/api/__init__.py +0 -48
  161. snowflake/cli/api/cli_global_context.py +0 -247
  162. snowflake/cli/api/commands/__init__.py +0 -13
  163. snowflake/cli/api/commands/alias.py +0 -23
  164. snowflake/cli/api/commands/common.py +0 -25
  165. snowflake/cli/api/commands/decorators.py +0 -369
  166. snowflake/cli/api/commands/execution_metadata.py +0 -40
  167. snowflake/cli/api/commands/experimental_behaviour.py +0 -18
  168. snowflake/cli/api/commands/flags.py +0 -561
  169. snowflake/cli/api/commands/overrideable_parameter.py +0 -143
  170. snowflake/cli/api/commands/snow_typer.py +0 -247
  171. snowflake/cli/api/commands/utils.py +0 -18
  172. snowflake/cli/api/config.py +0 -380
  173. snowflake/cli/api/connections.py +0 -216
  174. snowflake/cli/api/console/__init__.py +0 -17
  175. snowflake/cli/api/console/abc.py +0 -94
  176. snowflake/cli/api/console/console.py +0 -134
  177. snowflake/cli/api/console/enum.py +0 -17
  178. snowflake/cli/api/constants.py +0 -90
  179. snowflake/cli/api/entities/common.py +0 -56
  180. snowflake/cli/api/entities/utils.py +0 -370
  181. snowflake/cli/api/errno.py +0 -28
  182. snowflake/cli/api/exceptions.py +0 -190
  183. snowflake/cli/api/feature_flags.py +0 -54
  184. snowflake/cli/api/identifiers.py +0 -190
  185. snowflake/cli/api/metrics.py +0 -92
  186. snowflake/cli/api/output/__init__.py +0 -13
  187. snowflake/cli/api/output/formats.py +0 -20
  188. snowflake/cli/api/output/types.py +0 -118
  189. snowflake/cli/api/plugins/__init__.py +0 -13
  190. snowflake/cli/api/plugins/command/__init__.py +0 -72
  191. snowflake/cli/api/plugins/command/plugin_hook_specs.py +0 -21
  192. snowflake/cli/api/plugins/plugin_config.py +0 -32
  193. snowflake/cli/api/project/__init__.py +0 -13
  194. snowflake/cli/api/project/definition.py +0 -126
  195. snowflake/cli/api/project/definition_conversion.py +0 -395
  196. snowflake/cli/api/project/definition_manager.py +0 -145
  197. snowflake/cli/api/project/errors.py +0 -56
  198. snowflake/cli/api/project/project_verification.py +0 -23
  199. snowflake/cli/api/project/schemas/__init__.py +0 -13
  200. snowflake/cli/api/project/schemas/entities/__init__.py +0 -13
  201. snowflake/cli/api/project/schemas/entities/common.py +0 -153
  202. snowflake/cli/api/project/schemas/entities/entities.py +0 -61
  203. snowflake/cli/api/project/schemas/project_definition.py +0 -330
  204. snowflake/cli/api/project/schemas/template.py +0 -77
  205. snowflake/cli/api/project/schemas/updatable_model.py +0 -202
  206. snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
  207. snowflake/cli/api/project/schemas/v1/identifier_model.py +0 -51
  208. snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
  209. snowflake/cli/api/project/schemas/v1/native_app/application.py +0 -61
  210. snowflake/cli/api/project/schemas/v1/native_app/native_app.py +0 -93
  211. snowflake/cli/api/project/schemas/v1/native_app/package.py +0 -84
  212. snowflake/cli/api/project/schemas/v1/native_app/path_mapping.py +0 -65
  213. snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
  214. snowflake/cli/api/project/schemas/v1/snowpark/argument.py +0 -28
  215. snowflake/cli/api/project/schemas/v1/snowpark/callable.py +0 -69
  216. snowflake/cli/api/project/schemas/v1/snowpark/snowpark.py +0 -36
  217. snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
  218. snowflake/cli/api/project/schemas/v1/streamlit/streamlit.py +0 -47
  219. snowflake/cli/api/project/util.py +0 -278
  220. snowflake/cli/api/rendering/__init__.py +0 -13
  221. snowflake/cli/api/rendering/jinja.py +0 -118
  222. snowflake/cli/api/rendering/project_definition_templates.py +0 -43
  223. snowflake/cli/api/rendering/project_templates.py +0 -98
  224. snowflake/cli/api/rendering/sql_templates.py +0 -105
  225. snowflake/cli/api/rest_api.py +0 -178
  226. snowflake/cli/api/sanitizers.py +0 -43
  227. snowflake/cli/api/secure_path.py +0 -360
  228. snowflake/cli/api/secure_utils.py +0 -118
  229. snowflake/cli/api/sql_execution.py +0 -280
  230. snowflake/cli/api/utils/__init__.py +0 -13
  231. snowflake/cli/api/utils/cursor.py +0 -34
  232. snowflake/cli/api/utils/definition_rendering.py +0 -415
  233. snowflake/cli/api/utils/dict_utils.py +0 -73
  234. snowflake/cli/api/utils/error_handling.py +0 -23
  235. snowflake/cli/api/utils/graph.py +0 -97
  236. snowflake/cli/api/utils/models.py +0 -63
  237. snowflake/cli/api/utils/naming_utils.py +0 -13
  238. snowflake/cli/api/utils/path_utils.py +0 -36
  239. snowflake/cli/api/utils/templating_functions.py +0 -144
  240. snowflake/cli/api/utils/types.py +0 -35
  241. snowflake_cli_labs-3.0.0rc4.dist-info/RECORD +0 -242
  242. snowflake_cli_labs-3.0.0rc4.dist-info/entry_points.txt +0 -2
  243. {snowflake_cli_labs-3.0.0rc4.dist-info → snowflake_cli_labs-3.0.1.dist-info}/WHEEL +0 -0
  244. {snowflake_cli_labs-3.0.0rc4.dist-info → snowflake_cli_labs-3.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,380 +0,0 @@
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 logging
18
- import os
19
- import warnings
20
- from contextlib import contextmanager
21
- from dataclasses import asdict, dataclass, field
22
- from pathlib import Path
23
- from typing import Any, Dict, Optional, Union
24
-
25
- import tomlkit
26
- from click import ClickException
27
- from snowflake.cli.api.exceptions import (
28
- ConfigFileTooWidePermissionsError,
29
- MissingConfiguration,
30
- UnsupportedConfigSectionTypeError,
31
- )
32
- from snowflake.cli.api.secure_path import SecurePath
33
- from snowflake.cli.api.secure_utils import (
34
- file_permissions_are_strict,
35
- windows_get_not_whitelisted_users_with_access,
36
- )
37
- from snowflake.cli.api.utils.types import try_cast_to_bool
38
- from snowflake.connector.compat import IS_WINDOWS
39
- from snowflake.connector.config_manager import CONFIG_MANAGER
40
- from snowflake.connector.constants import CONFIG_FILE, CONNECTIONS_FILE
41
- from snowflake.connector.errors import ConfigSourceError, MissingConfigOptionError
42
- from tomlkit import TOMLDocument, dump
43
- from tomlkit.container import Container
44
- from tomlkit.exceptions import NonExistentKey
45
- from tomlkit.items import Table
46
-
47
- log = logging.getLogger(__name__)
48
-
49
-
50
- class Empty:
51
- pass
52
-
53
-
54
- CONNECTIONS_SECTION = "connections"
55
- CLI_SECTION = "cli"
56
- LOGS_SECTION = "logs"
57
- PLUGINS_SECTION = "plugins"
58
-
59
- LOGS_SECTION_PATH = [CLI_SECTION, LOGS_SECTION]
60
- PLUGINS_SECTION_PATH = [CLI_SECTION, PLUGINS_SECTION]
61
- FEATURE_FLAGS_SECTION_PATH = [CLI_SECTION, "features"]
62
-
63
- CONFIG_MANAGER.add_option(
64
- name=CLI_SECTION,
65
- parse_str=tomlkit.parse,
66
- default=dict(),
67
- )
68
-
69
-
70
- @dataclass
71
- class ConnectionConfig:
72
- account: Optional[str] = None
73
- user: Optional[str] = None
74
- password: Optional[str] = field(default=None, repr=False)
75
- host: Optional[str] = None
76
- region: Optional[str] = None
77
- port: Optional[int] = None
78
- database: Optional[str] = None
79
- schema: Optional[str] = None
80
- warehouse: Optional[str] = None
81
- role: Optional[str] = None
82
- authenticator: Optional[str] = None
83
- private_key_file: Optional[str] = None
84
- token_file_path: Optional[str] = None
85
-
86
- _other_settings: dict = field(default_factory=lambda: {})
87
-
88
- @classmethod
89
- def from_dict(cls, config_dict: dict) -> ConnectionConfig:
90
- known_settings = {}
91
- other_settings = {}
92
- for key, value in config_dict.items():
93
- if key in cls.__dict__:
94
- known_settings[key] = value
95
- else:
96
- other_settings[key] = value
97
- return cls(**known_settings, _other_settings=other_settings)
98
-
99
- def to_dict_of_known_non_empty_values(self) -> dict:
100
- return {
101
- k: v
102
- for k, v in asdict(self).items()
103
- if k != "_other_settings" and v is not None
104
- }
105
-
106
- def _non_empty_other_values(self) -> dict:
107
- return {k: v for k, v in self._other_settings.items() if v is not None}
108
-
109
- def to_dict_of_all_non_empty_values(self) -> dict:
110
- return {
111
- **self.to_dict_of_known_non_empty_values(),
112
- **self._non_empty_other_values(),
113
- }
114
-
115
-
116
- def config_init(config_file: Optional[Path]):
117
- """
118
- Initializes the app configuration. Config provided via cli flag takes precedence.
119
- If config file does not exist we create an empty one.
120
- """
121
- from snowflake.cli._app.loggers import create_initial_loggers
122
-
123
- if config_file:
124
- CONFIG_MANAGER.file_path = config_file
125
- else:
126
- _check_default_config_files_permissions()
127
- if not CONFIG_MANAGER.file_path.exists():
128
- _initialise_config(CONFIG_MANAGER.file_path)
129
- _read_config_file()
130
- create_initial_loggers()
131
-
132
-
133
- def add_connection_to_proper_file(name: str, connection_config: ConnectionConfig):
134
- if CONNECTIONS_FILE.exists():
135
- existing_connections = _read_connections_toml()
136
- existing_connections.update(
137
- {name: connection_config.to_dict_of_all_non_empty_values()}
138
- )
139
- _update_connections_toml(existing_connections)
140
- return CONNECTIONS_FILE
141
- else:
142
- set_config_value(
143
- section=CONNECTIONS_SECTION,
144
- key=name,
145
- value=connection_config.to_dict_of_all_non_empty_values(),
146
- )
147
- return CONFIG_MANAGER.file_path
148
-
149
-
150
- _DEFAULT_LOGS_CONFIG = {
151
- "save_logs": True,
152
- "path": str(CONFIG_MANAGER.file_path.parent / "logs"),
153
- "level": "info",
154
- }
155
-
156
- _DEFAULT_CLI_CONFIG = {LOGS_SECTION: _DEFAULT_LOGS_CONFIG}
157
-
158
-
159
- @contextmanager
160
- def _config_file():
161
- _read_config_file()
162
- conf_file_cache = CONFIG_MANAGER.conf_file_cache
163
- yield conf_file_cache
164
- _dump_config(conf_file_cache)
165
-
166
-
167
- def _read_config_file():
168
- with warnings.catch_warnings():
169
- if IS_WINDOWS:
170
- warnings.filterwarnings(
171
- action="ignore",
172
- message="Bad owner or permissions.*",
173
- module="snowflake.connector.config_manager",
174
- )
175
-
176
- if not file_permissions_are_strict(CONFIG_MANAGER.file_path):
177
- users = ", ".join(
178
- windows_get_not_whitelisted_users_with_access(
179
- CONFIG_MANAGER.file_path
180
- )
181
- )
182
- warnings.warn(
183
- f"Unauthorized users ({users}) have access to configuration file {CONFIG_MANAGER.file_path}.\n"
184
- f'Run `icacls "{CONFIG_MANAGER.file_path}" /deny <USER_ID>:F` on those users to restrict permissions.'
185
- )
186
-
187
- try:
188
- CONFIG_MANAGER.read_config()
189
- except ConfigSourceError as exception:
190
- raise ClickException(
191
- f"Configuration file seems to be corrupted. {str(exception.__cause__)}"
192
- )
193
-
194
-
195
- def _initialise_logs_section():
196
- with _config_file() as conf_file_cache:
197
- if conf_file_cache.get(CLI_SECTION) is None:
198
- conf_file_cache[CLI_SECTION] = _DEFAULT_CLI_CONFIG
199
- if conf_file_cache[CLI_SECTION].get(LOGS_SECTION) is None:
200
- conf_file_cache[CLI_SECTION][LOGS_SECTION] = _DEFAULT_LOGS_CONFIG
201
-
202
-
203
- def set_config_value(section: str | None, key: str, value: Any):
204
- with _config_file() as conf_file_cache:
205
- if section:
206
- if conf_file_cache.get(section) is None:
207
- conf_file_cache[section] = {}
208
- conf_file_cache[section][key] = value
209
- else:
210
- conf_file_cache[key] = value
211
-
212
-
213
- def get_logs_config() -> dict:
214
- logs_config = _DEFAULT_LOGS_CONFIG.copy()
215
- if config_section_exists(*LOGS_SECTION_PATH):
216
- logs_config.update(**get_config_section(*LOGS_SECTION_PATH))
217
- return logs_config
218
-
219
-
220
- def get_plugins_config() -> dict:
221
- if config_section_exists(*PLUGINS_SECTION_PATH):
222
- return get_config_section(*PLUGINS_SECTION_PATH)
223
- else:
224
- return {}
225
-
226
-
227
- def connection_exists(connection_name: str) -> bool:
228
- return config_section_exists(CONNECTIONS_SECTION, connection_name)
229
-
230
-
231
- def config_section_exists(*path) -> bool:
232
- try:
233
- _find_section(*path)
234
- return True
235
- except (KeyError, NonExistentKey, MissingConfigOptionError):
236
- return False
237
-
238
-
239
- def get_all_connections() -> dict[str, ConnectionConfig]:
240
- return {
241
- k: ConnectionConfig.from_dict(connection_dict)
242
- for k, connection_dict in get_config_section("connections").items()
243
- }
244
-
245
-
246
- def get_connection_dict(connection_name: str) -> dict:
247
- try:
248
- return get_config_section(CONNECTIONS_SECTION, connection_name)
249
- except KeyError:
250
- raise MissingConfiguration(f"Connection {connection_name} is not configured")
251
-
252
-
253
- def get_default_connection_name() -> str:
254
- return CONFIG_MANAGER["default_connection_name"]
255
-
256
-
257
- def get_default_connection_dict() -> dict:
258
- def_connection_name = get_default_connection_name()
259
- if not connection_exists(def_connection_name):
260
- raise MissingConfiguration(
261
- f"Couldn't find connection for default connection `{def_connection_name}`. "
262
- f"Specify connection name or configure default connection."
263
- )
264
- return get_connection_dict(def_connection_name)
265
-
266
-
267
- def get_config_section(*path) -> dict:
268
- section = _find_section(*path)
269
- if isinstance(section, Container):
270
- return {s: _merge_section_with_env(section[s], *path, s) for s in section}
271
- if isinstance(section, dict):
272
- return _merge_section_with_env(section, *path)
273
- raise UnsupportedConfigSectionTypeError(type(section))
274
-
275
-
276
- def get_config_value(*path, key: str, default: Optional[Any] = Empty) -> Any:
277
- """Looks for given key under nested path in toml file."""
278
- env_variable = get_env_value(*path, key=key)
279
- if env_variable:
280
- return env_variable
281
- try:
282
- return get_config_section(*path)[key]
283
- except (KeyError, NonExistentKey, MissingConfigOptionError):
284
- if default is not Empty:
285
- return default
286
- raise
287
-
288
-
289
- def get_config_bool_value(*path, key: str, default: Optional[Any] = Empty) -> bool:
290
- value = get_config_value(*path, key=key, default=default)
291
- try:
292
- return try_cast_to_bool(value)
293
- except ValueError:
294
- raise ClickException(
295
- f"Expected boolean value for {'.'.join((*path, key))} option."
296
- )
297
-
298
-
299
- def _initialise_config(config_file: Path) -> None:
300
- config_file = SecurePath(config_file)
301
- config_file.parent.mkdir(parents=True, exist_ok=True)
302
- config_file.touch()
303
- _initialise_logs_section()
304
- log.info("Created Snowflake configuration file at %s", CONFIG_MANAGER.file_path)
305
-
306
-
307
- def get_env_variable_name(*path, key: str) -> str:
308
- return ("_".join(["snowflake", *path, key])).upper()
309
-
310
-
311
- def get_env_value(*path, key: str) -> str | None:
312
- return os.environ.get(get_env_variable_name(*path, key=key))
313
-
314
-
315
- def _find_section(*path) -> TOMLDocument:
316
- section = CONFIG_MANAGER
317
- idx = 0
318
- while idx < len(path):
319
- section = section[path[idx]]
320
- idx += 1
321
- return section
322
-
323
-
324
- def _merge_section_with_env(section: Union[Table, Any], *path) -> Dict[str, str]:
325
- if isinstance(section, Table):
326
- env_variables = _get_envs_for_path(*path)
327
- section_copy = section.copy()
328
- section_copy.update(env_variables)
329
- return section_copy.unwrap()
330
- # It's a atomic value
331
- return section
332
-
333
-
334
- def _get_envs_for_path(*path) -> dict:
335
- env_variables_prefix = "_".join(["SNOWFLAKE"] + [p.upper() for p in path]) + "_"
336
- return {
337
- k.replace(env_variables_prefix, "").lower(): os.environ[k]
338
- for k in os.environ.keys()
339
- if k.startswith(env_variables_prefix)
340
- }
341
-
342
-
343
- def _dump_config(conf_file_cache: Dict):
344
- with SecurePath(CONFIG_MANAGER.file_path).open("w+") as fh:
345
- dump(conf_file_cache, fh)
346
-
347
-
348
- def _check_default_config_files_permissions() -> None:
349
- if CONNECTIONS_FILE.exists() and not file_permissions_are_strict(CONNECTIONS_FILE):
350
- raise ConfigFileTooWidePermissionsError(CONNECTIONS_FILE)
351
- if CONFIG_FILE.exists() and not file_permissions_are_strict(CONFIG_FILE):
352
- raise ConfigFileTooWidePermissionsError(CONFIG_FILE)
353
-
354
-
355
- from typing import Literal
356
-
357
-
358
- def get_feature_flags_section() -> Dict[str, bool | Literal["UNKNOWN"]]:
359
- if not config_section_exists(*FEATURE_FLAGS_SECTION_PATH):
360
- return {}
361
-
362
- flags = get_config_section(*FEATURE_FLAGS_SECTION_PATH)
363
-
364
- def _bool_or_unknown(value):
365
- try:
366
- return try_cast_to_bool(value)
367
- except ValueError:
368
- return "UNKNOWN"
369
-
370
- return {k: _bool_or_unknown(v) for k, v in flags.items()}
371
-
372
-
373
- def _read_connections_toml() -> dict:
374
- with open(CONNECTIONS_FILE, "r") as f:
375
- return tomlkit.loads(f.read()).unwrap()
376
-
377
-
378
- def _update_connections_toml(connections: dict):
379
- with open(CONNECTIONS_FILE, "w") as f:
380
- f.write(tomlkit.dumps(connections))
@@ -1,216 +0,0 @@
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 asyncio
18
- import logging
19
- import re
20
- import warnings
21
- from dataclasses import asdict, dataclass, field, fields, replace
22
- from pathlib import Path
23
- from typing import Optional
24
-
25
- from snowflake.cli.api.config import get_default_connection_name
26
- from snowflake.cli.api.exceptions import InvalidSchemaError
27
- from snowflake.connector import SnowflakeConnection
28
- from snowflake.connector.compat import IS_WINDOWS
29
-
30
- logger = logging.getLogger(__name__)
31
-
32
- schema_pattern = re.compile(r".+\..+")
33
-
34
-
35
- @dataclass
36
- class ConnectionContext:
37
- # FIXME: can reduce duplication using config.ConnectionConfig
38
- connection_name: Optional[str] = None
39
- host: Optional[str] = None
40
- port: Optional[int] = None
41
- account: Optional[str] = None
42
- database: Optional[str] = None
43
- role: Optional[str] = None
44
- schema: Optional[str] = None
45
- user: Optional[str] = None
46
- password: Optional[str] = field(default=None, repr=False)
47
- authenticator: Optional[str] = None
48
- private_key_file: Optional[str] = None
49
- warehouse: Optional[str] = None
50
- mfa_passcode: Optional[str] = None
51
- enable_diag: Optional[bool] = False
52
- diag_log_path: Optional[Path] = None
53
- diag_allowlist_path: Optional[Path] = None
54
- temporary_connection: bool = False
55
- session_token: Optional[str] = None
56
- master_token: Optional[str] = None
57
- token_file_path: Optional[Path] = None
58
-
59
- VALIDATED_FIELD_NAMES = ["schema"]
60
-
61
- def present_values_as_dict(self) -> dict:
62
- """Dictionary representation of this ConnectionContext for values that are not None"""
63
- return {k: v for (k, v) in asdict(self).items() if v is not None}
64
-
65
- def clone(self) -> ConnectionContext:
66
- return replace(self)
67
-
68
- def update(self, **updates):
69
- """
70
- Given a dictionary of property (key, value) mappings, update properties
71
- of this context object with equivalent names to the keys.
72
-
73
- Raises KeyError if a non-property is specified as a key.
74
- """
75
- field_map = {field.name: field for field in fields(self)}
76
- for key, value in updates.items():
77
- # ensure key represents a property
78
- if key not in field_map:
79
- raise KeyError(f"{key} is not a field of {self.__class__.__name__}")
80
- setattr(self, key, value)
81
-
82
- def __repr__(self) -> str:
83
- """Minimal repr where None values have their keys omitted."""
84
- items = [f"{k}={repr(v)}" for (k, v) in self.present_values_as_dict().items()]
85
- return f"{self.__class__.__name__}({', '.join(items)})"
86
-
87
- def __setattr__(self, prop, val):
88
- """Runs registered validators before setting fields."""
89
- if prop in self.VALIDATED_FIELD_NAMES:
90
- validate = getattr(self, f"validate_{prop}")
91
- validate(val)
92
- super().__setattr__(prop, val)
93
-
94
- def validate_schema(self, value: Optional[str]):
95
- if (
96
- value
97
- and not (value.startswith('"') and value.endswith('"'))
98
- # if schema is fully qualified name (db.schema)
99
- and schema_pattern.match(value)
100
- ):
101
- raise InvalidSchemaError(value)
102
-
103
- def validate_and_complete(self):
104
- """
105
- Ensure we can create a connection from this context.
106
- """
107
- if not self.temporary_connection and not self.connection_name:
108
- self.connection_name = get_default_connection_name()
109
-
110
- def build_connection(self):
111
- from snowflake.cli._app.snow_connector import connect_to_snowflake
112
-
113
- # Ignore warnings about bad owner or permissions on Windows
114
- # Telemetry omit our warning filter from config.py
115
- if IS_WINDOWS:
116
- warnings.filterwarnings(
117
- action="ignore",
118
- message="Bad owner or permissions.*",
119
- module="snowflake.connector.config_manager",
120
- )
121
-
122
- return connect_to_snowflake(**self.present_values_as_dict())
123
-
124
-
125
- class OpenConnectionCache:
126
- """
127
- A connection cache that transparently manages SnowflakeConnection objects
128
- and is keyed by ConnectionContext objects, e.g. cache[ctx].execute_string(...).
129
- Connections are automatically closed after CONNECTION_CLEANUP_SEC, but
130
- are guaranteed to be open (if config is valid) when returned by the cache.
131
- """
132
-
133
- connections: dict[str, SnowflakeConnection]
134
- cleanup_futures: dict[str, asyncio.TimerHandle]
135
-
136
- CONNECTION_CLEANUP_SEC: float = 10.0 * 60
137
- """Connections are closed this many seconds after the last time they are accessed."""
138
-
139
- def __init__(self):
140
- self.connections = {}
141
- self.cleanup_futures = {}
142
-
143
- def __getitem__(self, ctx):
144
- if not isinstance(ctx, ConnectionContext):
145
- raise ValueError(
146
- f"Expected key to be ConnectionContext but got {repr(ctx)}"
147
- )
148
- key = repr(ctx)
149
- if not self._has_open_connection(key):
150
- self._insert(key, ctx)
151
- self._touch(key)
152
- return self.connections[key]
153
-
154
- def clear(self):
155
- """Closes all connections and resets the cache to its initial state."""
156
- connection_keys = list(self.connections.keys())
157
- for key in connection_keys:
158
- self._cleanup(key)
159
-
160
- # if any orphaned futures still exist, clean them up too
161
- for future in self.cleanup_futures.values():
162
- future.cancel()
163
- self.cleanup_futures.clear()
164
-
165
- def _has_open_connection(self, key: str):
166
- return key in self.connections
167
-
168
- def _insert(self, key: str, ctx: ConnectionContext):
169
- try:
170
- # N.B. build_connection ultimately calls connect_to_snowflake, which
171
- # interpolates in connection dicts (from config) and environment variables.
172
- # This means that we could return a stale (incorrect) connection for the
173
- # given ConnectionContext if get_env_value or get_connection_dict would
174
- # have returned different values (i.e. env / config have changed).
175
- self.connections[key] = ctx.build_connection()
176
- except Exception:
177
- logger.debug(
178
- "ConnectionCache: failed to connect using %s; not caching.", key
179
- )
180
- raise
181
-
182
- def _cancel_cleanup_future_if_exists(self, key: str):
183
- if key in self.cleanup_futures:
184
- self.cleanup_futures.pop(key).cancel()
185
-
186
- def _touch(self, key: str):
187
- """
188
- Extend the lifetime of the cached connection at the given key.
189
- """
190
- loop = None
191
- try:
192
- loop = asyncio.get_event_loop()
193
- except RuntimeError:
194
- # Python 3.11+ will throw when no event loop;
195
- # Python 3.10 will issue a DeprecationWarning and return None
196
- pass
197
-
198
- if not loop:
199
- logger.debug(
200
- "ConnectionCache: no event loop; connections will close at exit."
201
- )
202
- return
203
-
204
- self._cancel_cleanup_future_if_exists(key)
205
- self.cleanup_futures[key] = loop.call_later(
206
- self.CONNECTION_CLEANUP_SEC, lambda: self._cleanup(key)
207
- )
208
-
209
- def _cleanup(self, key: str):
210
- """Closes the cached connection at the given key."""
211
- if key not in self.connections:
212
- logger.debug("Cleaning up connection %s, but not found in cache!", key)
213
-
214
- # doesn't cancel in-flight async queries
215
- self._cancel_cleanup_future_if_exists(key)
216
- self.connections.pop(key).close()
@@ -1,17 +0,0 @@
1
- # Copyright (c) 2024 Snowflake Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- from snowflake.cli.api.console.console import cli_console
16
-
17
- __all__ = ("cli_console",)
@@ -1,94 +0,0 @@
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 contextlib import contextmanager
19
- from typing import Callable, Iterator, Optional
20
-
21
- from rich import print as rich_print
22
- from rich.text import Text
23
- from snowflake.cli.api.cli_global_context import (
24
- _CliGlobalContextAccess,
25
- get_cli_context,
26
- )
27
-
28
-
29
- class AbstractConsole(ABC):
30
- """Interface for cli console implementation.
31
-
32
- Each console should have three methods implemented:
33
- - `step` - for more detailed information on steps
34
- - `warning` - for displaying messages in a style that makes it
35
- visually stand out from other output
36
- - `phase` a context manager for organising steps into logical group
37
- """
38
-
39
- _print_fn: Callable[[str], None]
40
- _in_phase: bool
41
-
42
- def __init__(self):
43
- super().__init__()
44
- self._in_phase = False
45
-
46
- @property
47
- def _cli_context(self) -> _CliGlobalContextAccess:
48
- return get_cli_context()
49
-
50
- @property
51
- def is_silent(self) -> bool:
52
- """Returns information whether intermediate output is muted."""
53
- return self._cli_context.silent
54
-
55
- @property
56
- def in_phase(self) -> bool:
57
- """Indicated whether output should be grouped."""
58
- return self._in_phase
59
-
60
- def _print(self, text: Text):
61
- if self.is_silent:
62
- return
63
- rich_print(text)
64
-
65
- @contextmanager
66
- @abstractmethod
67
- def phase(
68
- self,
69
- enter_message: str,
70
- exit_message: Optional[str] = None,
71
- ) -> Iterator[Callable[[str], None]]:
72
- """A context manager for organising steps into logical group."""
73
-
74
- @contextmanager
75
- @abstractmethod
76
- def indented(self):
77
- """
78
- A context manager for temporarily indenting messages and warnings. Phases and steps cannot be used in indented blocks,
79
- but multiple indented blocks can be nested (use sparingly).
80
- """
81
-
82
- @abstractmethod
83
- def step(self, message: str):
84
- """Displays a message to output."""
85
-
86
- @abstractmethod
87
- def message(self, _message: str):
88
- """Displays an informational message to output."""
89
-
90
- @abstractmethod
91
- def warning(self, message: str):
92
- """Displays message in a style that makes it visually stand out from other output.
93
-
94
- Intended for displaying messages related to important messages."""