snowflake-cli-labs 3.0.0rc5__py3-none-any.whl → 3.0.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.
- README.md +21 -0
- {snowflake_cli_labs-3.0.0rc5.dist-info → snowflake_cli_labs-3.0.2.dist-info}/METADATA +6 -96
- snowflake_cli_labs-3.0.2.dist-info/RECORD +5 -0
- snowflake/cli/__about__.py +0 -17
- snowflake/cli/__init__.py +0 -13
- snowflake/cli/_app/__init__.py +0 -22
- snowflake/cli/_app/__main__.py +0 -31
- snowflake/cli/_app/api_impl/__init__.py +0 -13
- snowflake/cli/_app/api_impl/plugin/__init__.py +0 -13
- snowflake/cli/_app/api_impl/plugin/plugin_config_provider_impl.py +0 -66
- snowflake/cli/_app/cli_app.py +0 -252
- snowflake/cli/_app/commands_registration/__init__.py +0 -33
- snowflake/cli/_app/commands_registration/builtin_plugins.py +0 -50
- snowflake/cli/_app/commands_registration/command_plugins_loader.py +0 -169
- snowflake/cli/_app/commands_registration/commands_registration_with_callbacks.py +0 -105
- snowflake/cli/_app/commands_registration/exception_logging.py +0 -26
- snowflake/cli/_app/commands_registration/threadsafe.py +0 -48
- snowflake/cli/_app/commands_registration/typer_registration.py +0 -153
- snowflake/cli/_app/constants.py +0 -19
- snowflake/cli/_app/dev/__init__.py +0 -13
- snowflake/cli/_app/dev/commands_structure.py +0 -48
- snowflake/cli/_app/dev/docs/__init__.py +0 -13
- snowflake/cli/_app/dev/docs/commands_docs_generator.py +0 -118
- snowflake/cli/_app/dev/docs/generator.py +0 -35
- snowflake/cli/_app/dev/docs/project_definition_docs_generator.py +0 -58
- snowflake/cli/_app/dev/docs/project_definition_generate_json_schema.py +0 -227
- snowflake/cli/_app/dev/docs/template_utils.py +0 -23
- snowflake/cli/_app/dev/docs/templates/definition_description.rst.jinja2 +0 -38
- snowflake/cli/_app/dev/docs/templates/overview.rst.jinja2 +0 -9
- snowflake/cli/_app/dev/docs/templates/usage.rst.jinja2 +0 -67
- snowflake/cli/_app/dev/pycharm_remote_debug.py +0 -46
- snowflake/cli/_app/loggers.py +0 -199
- snowflake/cli/_app/main_typer.py +0 -62
- snowflake/cli/_app/printing.py +0 -181
- snowflake/cli/_app/secret.py +0 -9
- snowflake/cli/_app/snow_connector.py +0 -309
- snowflake/cli/_app/telemetry.py +0 -220
- snowflake/cli/_app/version_check.py +0 -74
- snowflake/cli/_plugins/__init__.py +0 -13
- snowflake/cli/_plugins/connection/__init__.py +0 -13
- snowflake/cli/_plugins/connection/commands.py +0 -353
- snowflake/cli/_plugins/connection/plugin_spec.py +0 -30
- snowflake/cli/_plugins/connection/util.py +0 -195
- snowflake/cli/_plugins/cortex/__init__.py +0 -13
- snowflake/cli/_plugins/cortex/commands.py +0 -332
- snowflake/cli/_plugins/cortex/constants.py +0 -17
- snowflake/cli/_plugins/cortex/manager.py +0 -189
- snowflake/cli/_plugins/cortex/plugin_spec.py +0 -30
- snowflake/cli/_plugins/cortex/types.py +0 -22
- snowflake/cli/_plugins/git/__init__.py +0 -13
- snowflake/cli/_plugins/git/commands.py +0 -358
- snowflake/cli/_plugins/git/manager.py +0 -151
- snowflake/cli/_plugins/git/plugin_spec.py +0 -30
- snowflake/cli/_plugins/helpers/__init__.py +0 -13
- snowflake/cli/_plugins/helpers/commands.py +0 -90
- snowflake/cli/_plugins/helpers/plugin_spec.py +0 -30
- snowflake/cli/_plugins/init/__init__.py +0 -13
- snowflake/cli/_plugins/init/commands.py +0 -248
- snowflake/cli/_plugins/init/plugin_spec.py +0 -30
- snowflake/cli/_plugins/nativeapp/__init__.py +0 -13
- snowflake/cli/_plugins/nativeapp/artifacts.py +0 -757
- snowflake/cli/_plugins/nativeapp/bundle_context.py +0 -31
- snowflake/cli/_plugins/nativeapp/codegen/__init__.py +0 -13
- snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +0 -91
- snowflake/cli/_plugins/nativeapp/codegen/compiler.py +0 -149
- snowflake/cli/_plugins/nativeapp/codegen/sandbox.py +0 -306
- snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -249
- snowflake/cli/_plugins/nativeapp/codegen/setup/setup_driver.py.source +0 -59
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -181
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/extension_function_utils.py +0 -217
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/models.py +0 -61
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +0 -523
- snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +0 -114
- snowflake/cli/_plugins/nativeapp/commands.py +0 -559
- snowflake/cli/_plugins/nativeapp/common_flags.py +0 -44
- snowflake/cli/_plugins/nativeapp/constants.py +0 -27
- snowflake/cli/_plugins/nativeapp/entities/__init__.py +0 -0
- snowflake/cli/_plugins/nativeapp/entities/application.py +0 -878
- snowflake/cli/_plugins/nativeapp/entities/application_package.py +0 -1392
- snowflake/cli/_plugins/nativeapp/exceptions.py +0 -113
- snowflake/cli/_plugins/nativeapp/feature_flags.py +0 -24
- snowflake/cli/_plugins/nativeapp/manager.py +0 -415
- snowflake/cli/_plugins/nativeapp/plugin_spec.py +0 -30
- snowflake/cli/_plugins/nativeapp/policy.py +0 -53
- snowflake/cli/_plugins/nativeapp/project_model.py +0 -211
- snowflake/cli/_plugins/nativeapp/run_processor.py +0 -184
- snowflake/cli/_plugins/nativeapp/same_account_install_method.py +0 -70
- snowflake/cli/_plugins/nativeapp/teardown_processor.py +0 -70
- snowflake/cli/_plugins/nativeapp/utils.py +0 -98
- snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +0 -262
- snowflake/cli/_plugins/nativeapp/version/__init__.py +0 -13
- snowflake/cli/_plugins/nativeapp/version/commands.py +0 -141
- snowflake/cli/_plugins/nativeapp/version/version_processor.py +0 -98
- snowflake/cli/_plugins/notebook/__init__.py +0 -13
- snowflake/cli/_plugins/notebook/commands.py +0 -86
- snowflake/cli/_plugins/notebook/exceptions.py +0 -20
- snowflake/cli/_plugins/notebook/manager.py +0 -71
- snowflake/cli/_plugins/notebook/plugin_spec.py +0 -30
- snowflake/cli/_plugins/notebook/types.py +0 -15
- snowflake/cli/_plugins/object/__init__.py +0 -13
- snowflake/cli/_plugins/object/command_aliases.py +0 -95
- snowflake/cli/_plugins/object/commands.py +0 -180
- snowflake/cli/_plugins/object/common.py +0 -85
- snowflake/cli/_plugins/object/manager.py +0 -118
- snowflake/cli/_plugins/object/plugin_spec.py +0 -30
- snowflake/cli/_plugins/snowpark/__init__.py +0 -13
- snowflake/cli/_plugins/snowpark/commands.py +0 -450
- snowflake/cli/_plugins/snowpark/common.py +0 -268
- snowflake/cli/_plugins/snowpark/models.py +0 -150
- snowflake/cli/_plugins/snowpark/package/__init__.py +0 -13
- snowflake/cli/_plugins/snowpark/package/anaconda_packages.py +0 -199
- snowflake/cli/_plugins/snowpark/package/commands.py +0 -195
- snowflake/cli/_plugins/snowpark/package/manager.py +0 -44
- snowflake/cli/_plugins/snowpark/package/utils.py +0 -26
- snowflake/cli/_plugins/snowpark/package_utils.py +0 -354
- snowflake/cli/_plugins/snowpark/plugin_spec.py +0 -30
- snowflake/cli/_plugins/snowpark/snowpark_entity.py +0 -29
- snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +0 -173
- snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +0 -109
- snowflake/cli/_plugins/snowpark/snowpark_shared.py +0 -59
- snowflake/cli/_plugins/snowpark/zipper.py +0 -89
- snowflake/cli/_plugins/spcs/__init__.py +0 -33
- snowflake/cli/_plugins/spcs/common.py +0 -99
- snowflake/cli/_plugins/spcs/compute_pool/__init__.py +0 -13
- snowflake/cli/_plugins/spcs/compute_pool/commands.py +0 -241
- snowflake/cli/_plugins/spcs/compute_pool/manager.py +0 -121
- snowflake/cli/_plugins/spcs/image_registry/__init__.py +0 -13
- snowflake/cli/_plugins/spcs/image_registry/commands.py +0 -65
- snowflake/cli/_plugins/spcs/image_registry/manager.py +0 -105
- snowflake/cli/_plugins/spcs/image_repository/__init__.py +0 -13
- snowflake/cli/_plugins/spcs/image_repository/commands.py +0 -202
- snowflake/cli/_plugins/spcs/image_repository/manager.py +0 -84
- snowflake/cli/_plugins/spcs/plugin_spec.py +0 -30
- snowflake/cli/_plugins/spcs/services/__init__.py +0 -13
- snowflake/cli/_plugins/spcs/services/commands.py +0 -345
- snowflake/cli/_plugins/spcs/services/manager.py +0 -208
- snowflake/cli/_plugins/sql/__init__.py +0 -13
- snowflake/cli/_plugins/sql/commands.py +0 -86
- snowflake/cli/_plugins/sql/manager.py +0 -92
- snowflake/cli/_plugins/sql/plugin_spec.py +0 -30
- snowflake/cli/_plugins/sql/snowsql_templating.py +0 -28
- snowflake/cli/_plugins/stage/__init__.py +0 -13
- snowflake/cli/_plugins/stage/commands.py +0 -264
- snowflake/cli/_plugins/stage/diff.py +0 -280
- snowflake/cli/_plugins/stage/manager.py +0 -582
- snowflake/cli/_plugins/stage/md5.py +0 -160
- snowflake/cli/_plugins/stage/plugin_spec.py +0 -30
- snowflake/cli/_plugins/stage/utils.py +0 -54
- snowflake/cli/_plugins/streamlit/__init__.py +0 -13
- snowflake/cli/_plugins/streamlit/commands.py +0 -195
- snowflake/cli/_plugins/streamlit/manager.py +0 -220
- snowflake/cli/_plugins/streamlit/plugin_spec.py +0 -30
- snowflake/cli/_plugins/streamlit/streamlit_entity.py +0 -12
- snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +0 -66
- snowflake/cli/_plugins/workspace/__init__.py +0 -13
- snowflake/cli/_plugins/workspace/action_context.py +0 -18
- snowflake/cli/_plugins/workspace/commands.py +0 -306
- snowflake/cli/_plugins/workspace/manager.py +0 -74
- snowflake/cli/_plugins/workspace/plugin_spec.py +0 -30
- snowflake/cli/api/__init__.py +0 -48
- snowflake/cli/api/cli_global_context.py +0 -247
- snowflake/cli/api/commands/__init__.py +0 -13
- snowflake/cli/api/commands/alias.py +0 -23
- snowflake/cli/api/commands/common.py +0 -25
- snowflake/cli/api/commands/decorators.py +0 -369
- snowflake/cli/api/commands/execution_metadata.py +0 -40
- snowflake/cli/api/commands/experimental_behaviour.py +0 -18
- snowflake/cli/api/commands/flags.py +0 -561
- snowflake/cli/api/commands/overrideable_parameter.py +0 -143
- snowflake/cli/api/commands/snow_typer.py +0 -247
- snowflake/cli/api/commands/utils.py +0 -18
- snowflake/cli/api/config.py +0 -380
- snowflake/cli/api/connections.py +0 -216
- snowflake/cli/api/console/__init__.py +0 -17
- snowflake/cli/api/console/abc.py +0 -94
- snowflake/cli/api/console/console.py +0 -134
- snowflake/cli/api/console/enum.py +0 -17
- snowflake/cli/api/constants.py +0 -90
- snowflake/cli/api/entities/common.py +0 -56
- snowflake/cli/api/entities/utils.py +0 -370
- snowflake/cli/api/errno.py +0 -28
- snowflake/cli/api/exceptions.py +0 -190
- snowflake/cli/api/feature_flags.py +0 -54
- snowflake/cli/api/identifiers.py +0 -190
- snowflake/cli/api/metrics.py +0 -92
- snowflake/cli/api/output/__init__.py +0 -13
- snowflake/cli/api/output/formats.py +0 -20
- snowflake/cli/api/output/types.py +0 -118
- snowflake/cli/api/plugins/__init__.py +0 -13
- snowflake/cli/api/plugins/command/__init__.py +0 -72
- snowflake/cli/api/plugins/command/plugin_hook_specs.py +0 -21
- snowflake/cli/api/plugins/plugin_config.py +0 -32
- snowflake/cli/api/project/__init__.py +0 -13
- snowflake/cli/api/project/definition.py +0 -126
- snowflake/cli/api/project/definition_conversion.py +0 -400
- snowflake/cli/api/project/definition_manager.py +0 -145
- snowflake/cli/api/project/errors.py +0 -56
- snowflake/cli/api/project/project_verification.py +0 -23
- snowflake/cli/api/project/schemas/__init__.py +0 -13
- snowflake/cli/api/project/schemas/entities/__init__.py +0 -13
- snowflake/cli/api/project/schemas/entities/common.py +0 -153
- snowflake/cli/api/project/schemas/entities/entities.py +0 -61
- snowflake/cli/api/project/schemas/project_definition.py +0 -330
- snowflake/cli/api/project/schemas/template.py +0 -77
- snowflake/cli/api/project/schemas/updatable_model.py +0 -202
- snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
- snowflake/cli/api/project/schemas/v1/identifier_model.py +0 -51
- snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
- snowflake/cli/api/project/schemas/v1/native_app/application.py +0 -61
- snowflake/cli/api/project/schemas/v1/native_app/native_app.py +0 -93
- snowflake/cli/api/project/schemas/v1/native_app/package.py +0 -84
- snowflake/cli/api/project/schemas/v1/native_app/path_mapping.py +0 -65
- snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
- snowflake/cli/api/project/schemas/v1/snowpark/argument.py +0 -28
- snowflake/cli/api/project/schemas/v1/snowpark/callable.py +0 -69
- snowflake/cli/api/project/schemas/v1/snowpark/snowpark.py +0 -36
- snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
- snowflake/cli/api/project/schemas/v1/streamlit/streamlit.py +0 -47
- snowflake/cli/api/project/util.py +0 -278
- snowflake/cli/api/rendering/__init__.py +0 -13
- snowflake/cli/api/rendering/jinja.py +0 -118
- snowflake/cli/api/rendering/project_definition_templates.py +0 -43
- snowflake/cli/api/rendering/project_templates.py +0 -98
- snowflake/cli/api/rendering/sql_templates.py +0 -105
- snowflake/cli/api/rest_api.py +0 -178
- snowflake/cli/api/sanitizers.py +0 -43
- snowflake/cli/api/secure_path.py +0 -360
- snowflake/cli/api/secure_utils.py +0 -118
- snowflake/cli/api/sql_execution.py +0 -280
- snowflake/cli/api/utils/__init__.py +0 -13
- snowflake/cli/api/utils/cursor.py +0 -34
- snowflake/cli/api/utils/definition_rendering.py +0 -415
- snowflake/cli/api/utils/dict_utils.py +0 -73
- snowflake/cli/api/utils/error_handling.py +0 -23
- snowflake/cli/api/utils/graph.py +0 -97
- snowflake/cli/api/utils/models.py +0 -63
- snowflake/cli/api/utils/naming_utils.py +0 -13
- snowflake/cli/api/utils/path_utils.py +0 -36
- snowflake/cli/api/utils/templating_functions.py +0 -144
- snowflake/cli/api/utils/types.py +0 -35
- snowflake_cli_labs-3.0.0rc5.dist-info/RECORD +0 -242
- snowflake_cli_labs-3.0.0rc5.dist-info/entry_points.txt +0 -2
- {snowflake_cli_labs-3.0.0rc5.dist-info → snowflake_cli_labs-3.0.2.dist-info}/WHEEL +0 -0
- {snowflake_cli_labs-3.0.0rc5.dist-info → snowflake_cli_labs-3.0.2.dist-info}/licenses/LICENSE +0 -0
snowflake/cli/api/config.py
DELETED
|
@@ -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))
|
snowflake/cli/api/connections.py
DELETED
|
@@ -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",)
|
snowflake/cli/api/console/abc.py
DELETED
|
@@ -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."""
|