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
|
@@ -1,309 +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 contextlib
|
|
18
|
-
import logging
|
|
19
|
-
import os
|
|
20
|
-
from typing import Dict, Optional
|
|
21
|
-
|
|
22
|
-
import snowflake.connector
|
|
23
|
-
from click.exceptions import ClickException
|
|
24
|
-
from snowflake.cli._app.constants import (
|
|
25
|
-
PARAM_APPLICATION_NAME,
|
|
26
|
-
)
|
|
27
|
-
from snowflake.cli._app.secret import SecretType
|
|
28
|
-
from snowflake.cli._app.telemetry import command_info
|
|
29
|
-
from snowflake.cli.api.config import (
|
|
30
|
-
get_connection_dict,
|
|
31
|
-
get_env_value,
|
|
32
|
-
)
|
|
33
|
-
from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB
|
|
34
|
-
from snowflake.cli.api.exceptions import (
|
|
35
|
-
InvalidConnectionConfiguration,
|
|
36
|
-
SnowflakeConnectionError,
|
|
37
|
-
)
|
|
38
|
-
from snowflake.cli.api.secure_path import SecurePath
|
|
39
|
-
from snowflake.connector import SnowflakeConnection
|
|
40
|
-
from snowflake.connector.errors import DatabaseError, ForbiddenError
|
|
41
|
-
|
|
42
|
-
log = logging.getLogger(__name__)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
ENCRYPTED_PKCS8_PK_HEADER = b"-----BEGIN ENCRYPTED PRIVATE KEY-----"
|
|
46
|
-
UNENCRYPTED_PKCS8_PK_HEADER = b"-----BEGIN PRIVATE KEY-----"
|
|
47
|
-
|
|
48
|
-
# connection keys that can be set using SNOWFLAKE_* env vars
|
|
49
|
-
SUPPORTED_ENV_OVERRIDES = [
|
|
50
|
-
"account",
|
|
51
|
-
"user",
|
|
52
|
-
"password",
|
|
53
|
-
"authenticator",
|
|
54
|
-
"private_key_file",
|
|
55
|
-
"private_key_path",
|
|
56
|
-
"database",
|
|
57
|
-
"schema",
|
|
58
|
-
"role",
|
|
59
|
-
"warehouse",
|
|
60
|
-
"session_token",
|
|
61
|
-
"master_token",
|
|
62
|
-
"token_file_path",
|
|
63
|
-
]
|
|
64
|
-
|
|
65
|
-
# mapping of found key -> key to set
|
|
66
|
-
CONNECTION_KEY_ALIASES = {"private_key_path": "private_key_file"}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def _resolve_alias(key_or_alias: str):
|
|
70
|
-
"""
|
|
71
|
-
Given the key of an override / env var, what key should it be set as in the connection parameters?
|
|
72
|
-
"""
|
|
73
|
-
return CONNECTION_KEY_ALIASES.get(key_or_alias, key_or_alias)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def connect_to_snowflake(
|
|
77
|
-
temporary_connection: bool = False,
|
|
78
|
-
mfa_passcode: Optional[str] = None,
|
|
79
|
-
enable_diag: Optional[bool] = False,
|
|
80
|
-
diag_log_path: Optional[str] = None,
|
|
81
|
-
diag_allowlist_path: Optional[str] = None,
|
|
82
|
-
connection_name: Optional[str] = None,
|
|
83
|
-
**overrides,
|
|
84
|
-
) -> SnowflakeConnection:
|
|
85
|
-
if temporary_connection and connection_name:
|
|
86
|
-
raise ClickException("Can't use connection name and temporary connection.")
|
|
87
|
-
elif not temporary_connection and not connection_name:
|
|
88
|
-
raise ClickException(
|
|
89
|
-
"One of connection name or temporary connection is required."
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
using_session_token = (
|
|
93
|
-
"session_token" in overrides and overrides["session_token"] is not None
|
|
94
|
-
)
|
|
95
|
-
using_master_token = (
|
|
96
|
-
"master_token" in overrides and overrides["master_token"] is not None
|
|
97
|
-
)
|
|
98
|
-
_raise_errors_related_to_session_token(
|
|
99
|
-
temporary_connection, using_session_token, using_master_token
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
if connection_name:
|
|
103
|
-
connection_parameters = {
|
|
104
|
-
_resolve_alias(k): v
|
|
105
|
-
for k, v in get_connection_dict(connection_name).items()
|
|
106
|
-
}
|
|
107
|
-
elif temporary_connection:
|
|
108
|
-
connection_parameters = {} # we will apply overrides in next step
|
|
109
|
-
|
|
110
|
-
# Apply overrides to connection details
|
|
111
|
-
# (1) Command line override case
|
|
112
|
-
for key, value in overrides.items():
|
|
113
|
-
if value is not None:
|
|
114
|
-
connection_parameters[_resolve_alias(key)] = value
|
|
115
|
-
|
|
116
|
-
# (2) Generic environment variable case
|
|
117
|
-
# ... apply only if value not passed via flag or connection variable
|
|
118
|
-
for key in SUPPORTED_ENV_OVERRIDES:
|
|
119
|
-
generic_env_value = get_env_value(key=key)
|
|
120
|
-
connection_key = _resolve_alias(key)
|
|
121
|
-
if connection_key not in connection_parameters and generic_env_value:
|
|
122
|
-
connection_parameters[connection_key] = generic_env_value
|
|
123
|
-
|
|
124
|
-
# Clean up connection params
|
|
125
|
-
connection_parameters = {
|
|
126
|
-
k: v for k, v in connection_parameters.items() if v is not None
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
update_connection_details_with_private_key(connection_parameters)
|
|
130
|
-
|
|
131
|
-
if mfa_passcode:
|
|
132
|
-
connection_parameters["passcode"] = mfa_passcode
|
|
133
|
-
|
|
134
|
-
if connection_parameters.get("authenticator") == "username_password_mfa":
|
|
135
|
-
connection_parameters["client_request_mfa_token"] = True
|
|
136
|
-
|
|
137
|
-
if enable_diag:
|
|
138
|
-
connection_parameters["enable_connection_diag"] = enable_diag
|
|
139
|
-
if diag_log_path:
|
|
140
|
-
connection_parameters["connection_diag_log_path"] = diag_log_path
|
|
141
|
-
if diag_allowlist_path:
|
|
142
|
-
connection_parameters[
|
|
143
|
-
"connection_diag_allowlist_path"
|
|
144
|
-
] = diag_allowlist_path
|
|
145
|
-
|
|
146
|
-
# Make sure the connection is not closed if it was shared to the SnowCLI, instead of being created in the SnowCLI
|
|
147
|
-
_avoid_closing_the_connection_if_it_was_shared(
|
|
148
|
-
using_session_token, using_master_token, connection_parameters
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
_update_connection_application_name(connection_parameters)
|
|
152
|
-
|
|
153
|
-
try:
|
|
154
|
-
# Whatever output is generated when creating connection,
|
|
155
|
-
# we don't want it in our output. This is particularly important
|
|
156
|
-
# for cases when external browser and json format are used.
|
|
157
|
-
# Redirecting both stdout and stderr for offline usage.
|
|
158
|
-
with contextlib.redirect_stdout(None), contextlib.redirect_stderr(None):
|
|
159
|
-
return snowflake.connector.connect(
|
|
160
|
-
application=command_info(),
|
|
161
|
-
**connection_parameters,
|
|
162
|
-
)
|
|
163
|
-
except ForbiddenError as err:
|
|
164
|
-
raise SnowflakeConnectionError(err)
|
|
165
|
-
except DatabaseError as err:
|
|
166
|
-
raise InvalidConnectionConfiguration(err.msg)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
def _avoid_closing_the_connection_if_it_was_shared(
|
|
170
|
-
using_session_token: bool, using_master_token: bool, connection_parameters: Dict
|
|
171
|
-
):
|
|
172
|
-
if using_session_token and using_master_token:
|
|
173
|
-
connection_parameters["server_session_keep_alive"] = True
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
def _raise_errors_related_to_session_token(
|
|
177
|
-
temporary_connection: bool, using_session_token: bool, using_master_token: bool
|
|
178
|
-
):
|
|
179
|
-
if not temporary_connection and (using_session_token or using_master_token):
|
|
180
|
-
raise ClickException(
|
|
181
|
-
"When using a session or master token, you must use a temporary connection"
|
|
182
|
-
)
|
|
183
|
-
if using_session_token and not using_master_token:
|
|
184
|
-
raise ClickException(
|
|
185
|
-
"When using a session token, you must provide the corresponding master token"
|
|
186
|
-
)
|
|
187
|
-
if using_master_token and not using_session_token:
|
|
188
|
-
raise ClickException(
|
|
189
|
-
"When using a master token, you must provide the corresponding session token"
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
def update_connection_details_with_private_key(connection_parameters: Dict):
|
|
194
|
-
if "private_key_file" in connection_parameters:
|
|
195
|
-
_load_private_key(connection_parameters, "private_key_file")
|
|
196
|
-
elif "private_key_path" in connection_parameters:
|
|
197
|
-
_load_private_key(connection_parameters, "private_key_path")
|
|
198
|
-
elif "private_key_raw" in connection_parameters:
|
|
199
|
-
_load_private_key_from_parameters(connection_parameters, "private_key_raw")
|
|
200
|
-
return connection_parameters
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
def _load_private_key(connection_parameters: Dict, private_key_var_name: str) -> None:
|
|
204
|
-
if connection_parameters.get("authenticator") == "SNOWFLAKE_JWT":
|
|
205
|
-
private_key_pem = _load_pem_from_file(
|
|
206
|
-
connection_parameters[private_key_var_name]
|
|
207
|
-
)
|
|
208
|
-
private_key = _load_pem_to_der(private_key_pem)
|
|
209
|
-
connection_parameters["private_key"] = private_key.value
|
|
210
|
-
del connection_parameters[private_key_var_name]
|
|
211
|
-
else:
|
|
212
|
-
raise ClickException(
|
|
213
|
-
"Private Key authentication requires authenticator set to SNOWFLAKE_JWT"
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
def _load_private_key_from_parameters(
|
|
218
|
-
connection_parameters: Dict, private_key_var_name: str
|
|
219
|
-
) -> None:
|
|
220
|
-
if connection_parameters.get("authenticator") == "SNOWFLAKE_JWT":
|
|
221
|
-
private_key_pem = _load_pem_from_parameters(
|
|
222
|
-
connection_parameters[private_key_var_name]
|
|
223
|
-
)
|
|
224
|
-
private_key = _load_pem_to_der(private_key_pem)
|
|
225
|
-
connection_parameters["private_key"] = private_key.value
|
|
226
|
-
del connection_parameters[private_key_var_name]
|
|
227
|
-
else:
|
|
228
|
-
raise ClickException(
|
|
229
|
-
"Private Key authentication requires authenticator set to SNOWFLAKE_JWT"
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
def _update_connection_application_name(connection_parameters: Dict):
|
|
234
|
-
"""Update version and name of app handling connection."""
|
|
235
|
-
connection_application_params = {
|
|
236
|
-
"application_name": PARAM_APPLICATION_NAME,
|
|
237
|
-
}
|
|
238
|
-
connection_parameters.update(connection_application_params)
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
def _load_pem_from_file(private_key_file: str) -> SecretType:
|
|
242
|
-
with SecurePath(private_key_file).open(
|
|
243
|
-
"rb", read_file_limit_mb=DEFAULT_SIZE_LIMIT_MB
|
|
244
|
-
) as f:
|
|
245
|
-
private_key_pem = SecretType(f.read())
|
|
246
|
-
return private_key_pem
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
def _load_pem_from_parameters(private_key_raw: str) -> SecretType:
|
|
250
|
-
return SecretType(private_key_raw.encode("utf-8"))
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
def _load_pem_to_der(private_key_pem: SecretType) -> SecretType:
|
|
254
|
-
"""
|
|
255
|
-
Given a private key file path (in PEM format), decode key data into DER
|
|
256
|
-
format
|
|
257
|
-
"""
|
|
258
|
-
private_key_passphrase = SecretType(os.getenv("PRIVATE_KEY_PASSPHRASE", None))
|
|
259
|
-
if (
|
|
260
|
-
private_key_pem.value.startswith(ENCRYPTED_PKCS8_PK_HEADER)
|
|
261
|
-
and private_key_passphrase.value is None
|
|
262
|
-
):
|
|
263
|
-
raise ClickException(
|
|
264
|
-
"Encrypted private key, you must provide the"
|
|
265
|
-
"passphrase in the environment variable PRIVATE_KEY_PASSPHRASE"
|
|
266
|
-
)
|
|
267
|
-
|
|
268
|
-
if not private_key_pem.value.startswith(
|
|
269
|
-
ENCRYPTED_PKCS8_PK_HEADER
|
|
270
|
-
) and not private_key_pem.value.startswith(UNENCRYPTED_PKCS8_PK_HEADER):
|
|
271
|
-
raise ClickException(
|
|
272
|
-
"Private key provided is not in PKCS#8 format. Please use correct format."
|
|
273
|
-
)
|
|
274
|
-
|
|
275
|
-
if private_key_pem.value.startswith(UNENCRYPTED_PKCS8_PK_HEADER):
|
|
276
|
-
private_key_passphrase = SecretType(None)
|
|
277
|
-
|
|
278
|
-
return prepare_private_key(private_key_pem, private_key_passphrase)
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
def prepare_private_key(
|
|
282
|
-
private_key_pem: SecretType, private_key_passphrase: SecretType = SecretType(None)
|
|
283
|
-
):
|
|
284
|
-
from cryptography.hazmat.backends import default_backend
|
|
285
|
-
from cryptography.hazmat.primitives.serialization import (
|
|
286
|
-
Encoding,
|
|
287
|
-
NoEncryption,
|
|
288
|
-
PrivateFormat,
|
|
289
|
-
load_pem_private_key,
|
|
290
|
-
)
|
|
291
|
-
|
|
292
|
-
private_key = SecretType(
|
|
293
|
-
load_pem_private_key(
|
|
294
|
-
private_key_pem.value,
|
|
295
|
-
(
|
|
296
|
-
str.encode(private_key_passphrase.value)
|
|
297
|
-
if private_key_passphrase.value is not None
|
|
298
|
-
else private_key_passphrase.value
|
|
299
|
-
),
|
|
300
|
-
default_backend(),
|
|
301
|
-
)
|
|
302
|
-
)
|
|
303
|
-
return SecretType(
|
|
304
|
-
private_key.value.private_bytes(
|
|
305
|
-
encoding=Encoding.DER,
|
|
306
|
-
format=PrivateFormat.PKCS8,
|
|
307
|
-
encryption_algorithm=NoEncryption(),
|
|
308
|
-
)
|
|
309
|
-
)
|
snowflake/cli/_app/telemetry.py
DELETED
|
@@ -1,220 +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 platform
|
|
18
|
-
import sys
|
|
19
|
-
from enum import Enum, unique
|
|
20
|
-
from typing import Any, Dict, Union
|
|
21
|
-
|
|
22
|
-
import click
|
|
23
|
-
from snowflake.cli.__about__ import VERSION
|
|
24
|
-
from snowflake.cli._app.constants import PARAM_APPLICATION_NAME
|
|
25
|
-
from snowflake.cli.api.cli_global_context import (
|
|
26
|
-
_CliGlobalContextAccess,
|
|
27
|
-
get_cli_context,
|
|
28
|
-
)
|
|
29
|
-
from snowflake.cli.api.commands.execution_metadata import ExecutionMetadata
|
|
30
|
-
from snowflake.cli.api.config import get_feature_flags_section
|
|
31
|
-
from snowflake.cli.api.output.formats import OutputFormat
|
|
32
|
-
from snowflake.cli.api.utils.error_handling import ignore_exceptions
|
|
33
|
-
from snowflake.connector.telemetry import (
|
|
34
|
-
TelemetryData,
|
|
35
|
-
TelemetryField,
|
|
36
|
-
)
|
|
37
|
-
from snowflake.connector.time_util import get_time_millis
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@unique
|
|
41
|
-
class CLIInstallationSource(Enum):
|
|
42
|
-
BINARY = "binary"
|
|
43
|
-
PYPI = "pypi"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
@unique
|
|
47
|
-
class CLITelemetryField(Enum):
|
|
48
|
-
# Basic information
|
|
49
|
-
SOURCE = "source"
|
|
50
|
-
VERSION_CLI = "version_cli"
|
|
51
|
-
VERSION_PYTHON = "version_python"
|
|
52
|
-
VERSION_OS = "version_os"
|
|
53
|
-
INSTALLATION_SOURCE = "installation_source"
|
|
54
|
-
# Command execution context
|
|
55
|
-
COMMAND = "command"
|
|
56
|
-
COMMAND_GROUP = "command_group"
|
|
57
|
-
COMMAND_FLAGS = "command_flags"
|
|
58
|
-
COMMAND_EXECUTION_ID = "command_execution_id"
|
|
59
|
-
COMMAND_RESULT_STATUS = "command_result_status"
|
|
60
|
-
COMMAND_OUTPUT_TYPE = "command_output_type"
|
|
61
|
-
COMMAND_EXECUTION_TIME = "command_execution_time"
|
|
62
|
-
# Configuration
|
|
63
|
-
CONFIG_FEATURE_FLAGS = "config_feature_flags"
|
|
64
|
-
# Metrics
|
|
65
|
-
COUNTERS = "counters"
|
|
66
|
-
# Information
|
|
67
|
-
EVENT = "event"
|
|
68
|
-
ERROR_MSG = "error_msg"
|
|
69
|
-
ERROR_TYPE = "error_type"
|
|
70
|
-
IS_CLI_EXCEPTION = "is_cli_exception"
|
|
71
|
-
# Project context
|
|
72
|
-
PROJECT_DEFINITION_VERSION = "project_definition_version"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
class TelemetryEvent(Enum):
|
|
76
|
-
CMD_EXECUTION = "executing_command"
|
|
77
|
-
CMD_EXECUTION_ERROR = "error_executing_command"
|
|
78
|
-
CMD_EXECUTION_RESULT = "result_executing_command"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
TelemetryDict = Dict[Union[CLITelemetryField, TelemetryField], Any]
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def _get_command_metrics() -> TelemetryDict:
|
|
85
|
-
cli_context = get_cli_context()
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
CLITelemetryField.COUNTERS: {
|
|
89
|
-
**cli_context.metrics.counters,
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def _find_command_info() -> TelemetryDict:
|
|
95
|
-
ctx = click.get_current_context()
|
|
96
|
-
command_path = ctx.command_path.split(" ")[1:]
|
|
97
|
-
return {
|
|
98
|
-
CLITelemetryField.COMMAND: command_path,
|
|
99
|
-
CLITelemetryField.COMMAND_GROUP: command_path[0],
|
|
100
|
-
CLITelemetryField.COMMAND_FLAGS: {
|
|
101
|
-
k: ctx.get_parameter_source(k).name # type: ignore[attr-defined]
|
|
102
|
-
for k, v in ctx.params.items()
|
|
103
|
-
if v # noqa
|
|
104
|
-
},
|
|
105
|
-
CLITelemetryField.COMMAND_OUTPUT_TYPE: ctx.params.get(
|
|
106
|
-
"format", OutputFormat.TABLE
|
|
107
|
-
).value,
|
|
108
|
-
CLITelemetryField.PROJECT_DEFINITION_VERSION: str(_get_definition_version()),
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def _get_definition_version() -> str | None:
|
|
113
|
-
cli_context = get_cli_context()
|
|
114
|
-
if cli_context.project_definition:
|
|
115
|
-
return cli_context.project_definition.definition_version
|
|
116
|
-
return None
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
def _get_installation_source() -> CLIInstallationSource:
|
|
120
|
-
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
|
|
121
|
-
return CLIInstallationSource.BINARY
|
|
122
|
-
return CLIInstallationSource.PYPI
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def command_info() -> str:
|
|
126
|
-
info = _find_command_info()
|
|
127
|
-
command = ".".join(info[CLITelemetryField.COMMAND])
|
|
128
|
-
return f"{PARAM_APPLICATION_NAME}.{command}".upper()
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
def python_version() -> str:
|
|
132
|
-
py_ver = sys.version_info
|
|
133
|
-
return f"{py_ver.major}.{py_ver.minor}.{py_ver.micro}"
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
class CLITelemetryClient:
|
|
137
|
-
@property
|
|
138
|
-
def _ctx(self) -> _CliGlobalContextAccess:
|
|
139
|
-
return get_cli_context()
|
|
140
|
-
|
|
141
|
-
@staticmethod
|
|
142
|
-
def generate_telemetry_data_dict(
|
|
143
|
-
telemetry_payload: TelemetryDict,
|
|
144
|
-
) -> Dict[str, Any]:
|
|
145
|
-
data = {
|
|
146
|
-
CLITelemetryField.SOURCE: PARAM_APPLICATION_NAME,
|
|
147
|
-
CLITelemetryField.INSTALLATION_SOURCE: _get_installation_source().value,
|
|
148
|
-
CLITelemetryField.VERSION_CLI: VERSION,
|
|
149
|
-
CLITelemetryField.VERSION_OS: platform.platform(),
|
|
150
|
-
CLITelemetryField.VERSION_PYTHON: python_version(),
|
|
151
|
-
CLITelemetryField.CONFIG_FEATURE_FLAGS: {
|
|
152
|
-
k: str(v) for k, v in get_feature_flags_section().items()
|
|
153
|
-
},
|
|
154
|
-
**_find_command_info(),
|
|
155
|
-
**telemetry_payload,
|
|
156
|
-
}
|
|
157
|
-
# To map Enum to string, so we don't have to use .value every time
|
|
158
|
-
return {getattr(k, "value", k): v for k, v in data.items()} # type: ignore[arg-type]
|
|
159
|
-
|
|
160
|
-
@property
|
|
161
|
-
def _telemetry(self):
|
|
162
|
-
return self._ctx.connection._telemetry # noqa
|
|
163
|
-
|
|
164
|
-
def send(self, payload: TelemetryDict):
|
|
165
|
-
if self._telemetry:
|
|
166
|
-
message = self.generate_telemetry_data_dict(payload)
|
|
167
|
-
telemetry_data = TelemetryData.from_telemetry_data_dict(
|
|
168
|
-
from_dict=message, timestamp=get_time_millis()
|
|
169
|
-
)
|
|
170
|
-
self._telemetry.try_add_log_to_batch(telemetry_data)
|
|
171
|
-
|
|
172
|
-
def flush(self):
|
|
173
|
-
self._telemetry.send_batch()
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
_telemetry = CLITelemetryClient()
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
@ignore_exceptions()
|
|
180
|
-
def log_command_usage(execution: ExecutionMetadata):
|
|
181
|
-
_telemetry.send(
|
|
182
|
-
{
|
|
183
|
-
TelemetryField.KEY_TYPE: TelemetryEvent.CMD_EXECUTION.value,
|
|
184
|
-
CLITelemetryField.COMMAND_EXECUTION_ID: execution.execution_id,
|
|
185
|
-
}
|
|
186
|
-
)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
@ignore_exceptions()
|
|
190
|
-
def log_command_result(execution: ExecutionMetadata):
|
|
191
|
-
_telemetry.send(
|
|
192
|
-
{
|
|
193
|
-
TelemetryField.KEY_TYPE: TelemetryEvent.CMD_EXECUTION_RESULT.value,
|
|
194
|
-
CLITelemetryField.COMMAND_EXECUTION_ID: execution.execution_id,
|
|
195
|
-
CLITelemetryField.COMMAND_RESULT_STATUS: execution.status.value,
|
|
196
|
-
CLITelemetryField.COMMAND_EXECUTION_TIME: execution.get_duration(),
|
|
197
|
-
**_get_command_metrics(),
|
|
198
|
-
}
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
@ignore_exceptions()
|
|
203
|
-
def log_command_execution_error(exception: Exception, execution: ExecutionMetadata):
|
|
204
|
-
exception_type: str = type(exception).__name__
|
|
205
|
-
is_cli_exception: bool = issubclass(exception.__class__, click.ClickException)
|
|
206
|
-
_telemetry.send(
|
|
207
|
-
{
|
|
208
|
-
TelemetryField.KEY_TYPE: TelemetryEvent.CMD_EXECUTION_ERROR.value,
|
|
209
|
-
CLITelemetryField.COMMAND_EXECUTION_ID: execution.execution_id,
|
|
210
|
-
CLITelemetryField.ERROR_TYPE: exception_type,
|
|
211
|
-
CLITelemetryField.IS_CLI_EXCEPTION: is_cli_exception,
|
|
212
|
-
CLITelemetryField.COMMAND_EXECUTION_TIME: execution.get_duration(),
|
|
213
|
-
**_get_command_metrics(),
|
|
214
|
-
}
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
@ignore_exceptions()
|
|
219
|
-
def flush_telemetry():
|
|
220
|
-
_telemetry.flush()
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import time
|
|
3
|
-
|
|
4
|
-
import requests
|
|
5
|
-
from packaging.version import Version
|
|
6
|
-
from snowflake.cli.__about__ import VERSION
|
|
7
|
-
from snowflake.cli.api.console import cli_console
|
|
8
|
-
from snowflake.cli.api.secure_path import SecurePath
|
|
9
|
-
from snowflake.connector.config_manager import CONFIG_MANAGER
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def get_new_version_msg() -> str | None:
|
|
13
|
-
last = _VersionCache().get_last_version()
|
|
14
|
-
current = Version(VERSION)
|
|
15
|
-
if last and last > current:
|
|
16
|
-
return f"\nNew version of Snowflake CLI available. Newest: {last}, current: {VERSION}\n"
|
|
17
|
-
return None
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def show_new_version_banner_callback(msg):
|
|
21
|
-
def _callback(*args, **kwargs):
|
|
22
|
-
if msg:
|
|
23
|
-
cli_console.message(msg)
|
|
24
|
-
|
|
25
|
-
return _callback
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class _VersionCache:
|
|
29
|
-
_last_time = "last_time_check"
|
|
30
|
-
_version = "version"
|
|
31
|
-
_version_cache_file = SecurePath(
|
|
32
|
-
CONFIG_MANAGER.file_path.parent / ".cli_version.cache"
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
def __init__(self):
|
|
36
|
-
self._cache_file = _VersionCache._version_cache_file
|
|
37
|
-
|
|
38
|
-
def _save_latest_version(self, version: str):
|
|
39
|
-
data = {
|
|
40
|
-
_VersionCache._last_time: time.time(),
|
|
41
|
-
_VersionCache._version: str(version),
|
|
42
|
-
}
|
|
43
|
-
self._cache_file.write_text(json.dumps(data))
|
|
44
|
-
|
|
45
|
-
@staticmethod
|
|
46
|
-
def _get_version_from_pypi() -> str | None:
|
|
47
|
-
headers = {"Content-Type": "application/vnd.pypi.simple.v1+json"}
|
|
48
|
-
response = requests.get(
|
|
49
|
-
"https://pypi.org/pypi/snowflake-cli-labs/json", headers=headers, timeout=3
|
|
50
|
-
)
|
|
51
|
-
response.raise_for_status()
|
|
52
|
-
return response.json()["info"]["version"]
|
|
53
|
-
|
|
54
|
-
def _update_latest_version(self) -> Version | None:
|
|
55
|
-
version = self._get_version_from_pypi()
|
|
56
|
-
if version is None:
|
|
57
|
-
return None
|
|
58
|
-
self._save_latest_version(version)
|
|
59
|
-
return Version(version)
|
|
60
|
-
|
|
61
|
-
def _read_latest_version(self) -> Version | None:
|
|
62
|
-
if self._cache_file.exists():
|
|
63
|
-
data = json.loads(self._cache_file.read_text())
|
|
64
|
-
now = time.time()
|
|
65
|
-
if data[_VersionCache._last_time] > now - 60 * 60:
|
|
66
|
-
return Version(data[_VersionCache._version])
|
|
67
|
-
|
|
68
|
-
return self._update_latest_version()
|
|
69
|
-
|
|
70
|
-
def get_last_version(self) -> Version | None:
|
|
71
|
-
try:
|
|
72
|
-
return self._read_latest_version()
|
|
73
|
-
except: # anything, this it not crucial feature
|
|
74
|
-
return None
|
|
@@ -1,13 +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.
|
|
@@ -1,13 +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.
|