snowflake-cli-labs 2.6.0rc0__py3-none-any.whl → 2.6.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.
- snowflake/cli/__about__.py +1 -1
- snowflake/cli/api/config.py +3 -0
- snowflake/cli/api/rest_api.py +84 -25
- snowflake/cli/app/cli_app.py +0 -2
- snowflake/cli/app/loggers.py +7 -5
- snowflake/cli/plugins/object/commands.py +1 -1
- snowflake/cli/plugins/object/manager.py +2 -15
- {snowflake_cli_labs-2.6.0rc0.dist-info → snowflake_cli_labs-2.6.1.dist-info}/METADATA +1 -1
- {snowflake_cli_labs-2.6.0rc0.dist-info → snowflake_cli_labs-2.6.1.dist-info}/RECORD +12 -12
- {snowflake_cli_labs-2.6.0rc0.dist-info → snowflake_cli_labs-2.6.1.dist-info}/WHEEL +0 -0
- {snowflake_cli_labs-2.6.0rc0.dist-info → snowflake_cli_labs-2.6.1.dist-info}/entry_points.txt +0 -0
- {snowflake_cli_labs-2.6.0rc0.dist-info → snowflake_cli_labs-2.6.1.dist-info}/licenses/LICENSE +0 -0
snowflake/cli/__about__.py
CHANGED
snowflake/cli/api/config.py
CHANGED
|
@@ -114,6 +114,8 @@ def config_init(config_file: Optional[Path]):
|
|
|
114
114
|
Initializes the app configuration. Config provided via cli flag takes precedence.
|
|
115
115
|
If config file does not exist we create an empty one.
|
|
116
116
|
"""
|
|
117
|
+
from snowflake.cli.app.loggers import create_initial_loggers
|
|
118
|
+
|
|
117
119
|
if config_file:
|
|
118
120
|
CONFIG_MANAGER.file_path = config_file
|
|
119
121
|
else:
|
|
@@ -121,6 +123,7 @@ def config_init(config_file: Optional[Path]):
|
|
|
121
123
|
if not CONFIG_MANAGER.file_path.exists():
|
|
122
124
|
_initialise_config(CONFIG_MANAGER.file_path)
|
|
123
125
|
_read_config_file()
|
|
126
|
+
create_initial_loggers()
|
|
124
127
|
|
|
125
128
|
|
|
126
129
|
def add_connection(name: str, connection_config: ConnectionConfig):
|
snowflake/cli/api/rest_api.py
CHANGED
|
@@ -16,16 +16,27 @@ from __future__ import annotations
|
|
|
16
16
|
|
|
17
17
|
import json
|
|
18
18
|
import logging
|
|
19
|
-
from typing import Any, Dict,
|
|
19
|
+
from typing import Any, Dict, Optional
|
|
20
20
|
|
|
21
|
+
from click import ClickException
|
|
21
22
|
from snowflake.cli.api.constants import SF_REST_API_URL_PREFIX
|
|
22
23
|
from snowflake.connector.connection import SnowflakeConnection
|
|
23
|
-
from snowflake.connector.errors import InterfaceError
|
|
24
|
+
from snowflake.connector.errors import BadRequest, InterfaceError
|
|
24
25
|
from snowflake.connector.network import SnowflakeRestful
|
|
25
26
|
|
|
26
27
|
log = logging.getLogger(__name__)
|
|
27
28
|
|
|
28
29
|
|
|
30
|
+
def _pluralize_object_type(object_type: str) -> str:
|
|
31
|
+
"""
|
|
32
|
+
Pluralize object type without depending on OBJECT_TO_NAMES.
|
|
33
|
+
"""
|
|
34
|
+
if object_type.endswith("y"):
|
|
35
|
+
return object_type[:-1].lower() + "ies"
|
|
36
|
+
else:
|
|
37
|
+
return object_type.lower() + "s"
|
|
38
|
+
|
|
39
|
+
|
|
29
40
|
class RestApi:
|
|
30
41
|
def __init__(self, connection: SnowflakeConnection):
|
|
31
42
|
self.conn = connection
|
|
@@ -43,6 +54,13 @@ class RestApi:
|
|
|
43
54
|
return False
|
|
44
55
|
raise err
|
|
45
56
|
|
|
57
|
+
def _fetch_endpoint_exists(self, url: str) -> bool:
|
|
58
|
+
try:
|
|
59
|
+
result = self.send_rest_request(url, method="get")
|
|
60
|
+
return bool(result)
|
|
61
|
+
except BadRequest:
|
|
62
|
+
return False
|
|
63
|
+
|
|
46
64
|
def send_rest_request(
|
|
47
65
|
self, url: str, method: str, data: Optional[Dict[str, Any]] = None
|
|
48
66
|
):
|
|
@@ -75,12 +93,18 @@ class RestApi:
|
|
|
75
93
|
no_retry=True,
|
|
76
94
|
)
|
|
77
95
|
|
|
78
|
-
def
|
|
79
|
-
|
|
80
|
-
|
|
96
|
+
def _database_exists(self, db_name: str) -> bool:
|
|
97
|
+
url = f"{SF_REST_API_URL_PREFIX}/databases/{db_name}"
|
|
98
|
+
return self._fetch_endpoint_exists(url)
|
|
99
|
+
|
|
100
|
+
def _schema_exists(self, db_name: str, schema_name: str) -> bool:
|
|
101
|
+
url = f"{SF_REST_API_URL_PREFIX}/databases/{db_name}/schemas/{schema_name}"
|
|
102
|
+
return self._fetch_endpoint_exists(url)
|
|
103
|
+
|
|
104
|
+
def determine_url_for_create_query(self, object_type: str) -> str:
|
|
81
105
|
"""
|
|
82
106
|
Determine an url for creating an object of given type via REST API.
|
|
83
|
-
|
|
107
|
+
If URL cannot be determined, the function throws CannotDetermineCreateURLException exception.
|
|
84
108
|
|
|
85
109
|
URLs we check:
|
|
86
110
|
* /api/v2/<type>/
|
|
@@ -92,22 +116,57 @@ class RestApi:
|
|
|
92
116
|
To check whether an URL exists, we send read-only GET request (LIST endpoint,
|
|
93
117
|
which should imply CREATE endpoint).
|
|
94
118
|
"""
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
119
|
+
plural_object_type = _pluralize_object_type(object_type)
|
|
120
|
+
|
|
121
|
+
if self.get_endpoint_exists(
|
|
122
|
+
url := f"{SF_REST_API_URL_PREFIX}/{plural_object_type}/"
|
|
123
|
+
):
|
|
124
|
+
return url
|
|
125
|
+
|
|
126
|
+
db = self.conn.database
|
|
127
|
+
if not db:
|
|
128
|
+
raise DatabaseNotDefinedException(
|
|
129
|
+
"Database not defined in connection. Please try again with `--database` flag."
|
|
130
|
+
)
|
|
131
|
+
if not self._database_exists(db):
|
|
132
|
+
raise DatabaseNotExistsException(f"Database '{db}' does not exist.")
|
|
133
|
+
if self.get_endpoint_exists(
|
|
134
|
+
url := f"{SF_REST_API_URL_PREFIX}/databases/{db}/{plural_object_type}/"
|
|
135
|
+
):
|
|
136
|
+
return url
|
|
137
|
+
|
|
138
|
+
schema = self.conn.schema
|
|
139
|
+
if not schema:
|
|
140
|
+
raise SchemaNotDefinedException(
|
|
141
|
+
"Schema not defined in connection. Please try again with `--schema` flag."
|
|
142
|
+
)
|
|
143
|
+
if not self._schema_exists(db_name=db, schema_name=schema):
|
|
144
|
+
raise SchemaNotExistsException(f"Schema '{schema}' does not exist.")
|
|
145
|
+
if self.get_endpoint_exists(
|
|
146
|
+
url := f"{SF_REST_API_URL_PREFIX}/databases/{self.conn.database}/schemas/{self.conn.schema}/{plural_object_type}/"
|
|
147
|
+
):
|
|
148
|
+
return url
|
|
149
|
+
|
|
150
|
+
raise CannotDetermineCreateURLException(
|
|
151
|
+
f"Create operation for type {object_type} is not supported. Try using `sql -q 'CREATE ...'` command."
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class DatabaseNotDefinedException(ClickException):
|
|
156
|
+
pass
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class SchemaNotDefinedException(ClickException):
|
|
160
|
+
pass
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class DatabaseNotExistsException(ClickException):
|
|
164
|
+
pass
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class SchemaNotExistsException(ClickException):
|
|
168
|
+
pass
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class CannotDetermineCreateURLException(ClickException):
|
|
172
|
+
pass
|
snowflake/cli/app/cli_app.py
CHANGED
|
@@ -30,7 +30,6 @@ from snowflake.cli.api.config import config_init
|
|
|
30
30
|
from snowflake.cli.api.output.formats import OutputFormat
|
|
31
31
|
from snowflake.cli.api.output.types import CollectionResult
|
|
32
32
|
from snowflake.cli.api.secure_path import SecurePath
|
|
33
|
-
from snowflake.cli.app import loggers
|
|
34
33
|
from snowflake.cli.app.api_impl.plugin.plugin_config_provider_impl import (
|
|
35
34
|
PluginConfigProviderImpl,
|
|
36
35
|
)
|
|
@@ -89,7 +88,6 @@ def _commands_registration_callback(value: bool):
|
|
|
89
88
|
@_commands_registration.before
|
|
90
89
|
def _config_init_callback(configuration_file: Optional[Path]):
|
|
91
90
|
config_init(configuration_file)
|
|
92
|
-
loggers.create_initial_loggers()
|
|
93
91
|
|
|
94
92
|
|
|
95
93
|
@_commands_registration.before
|
snowflake/cli/app/loggers.py
CHANGED
|
@@ -20,9 +20,6 @@ from dataclasses import asdict, dataclass, field
|
|
|
20
20
|
from typing import Any, Dict, List
|
|
21
21
|
|
|
22
22
|
import typer
|
|
23
|
-
from snowflake.cli.api.config import (
|
|
24
|
-
get_logs_config,
|
|
25
|
-
)
|
|
26
23
|
from snowflake.cli.api.exceptions import InvalidLogsConfiguration
|
|
27
24
|
from snowflake.cli.api.secure_path import SecurePath
|
|
28
25
|
from snowflake.connector.errors import ConfigSourceError
|
|
@@ -103,6 +100,10 @@ def _remove_underscore_prefixes_from_keys(d: Dict[str, Any]) -> None:
|
|
|
103
100
|
|
|
104
101
|
class FileLogsConfig:
|
|
105
102
|
def __init__(self, debug: bool) -> None:
|
|
103
|
+
from snowflake.cli.api.config import (
|
|
104
|
+
get_logs_config,
|
|
105
|
+
)
|
|
106
|
+
|
|
106
107
|
config = get_logs_config()
|
|
107
108
|
|
|
108
109
|
self.path: SecurePath = SecurePath(config["path"])
|
|
@@ -142,8 +143,9 @@ def create_initial_loggers():
|
|
|
142
143
|
config = InitialLoggingConfig()
|
|
143
144
|
try:
|
|
144
145
|
file_logs_config = FileLogsConfig(debug=False)
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
if file_logs_config.save_logs:
|
|
147
|
+
config.handlers["file"]["filename"] = file_logs_config.filename
|
|
148
|
+
_configurate_logging(config)
|
|
147
149
|
except ConfigSourceError:
|
|
148
150
|
pass
|
|
149
151
|
|
|
@@ -33,7 +33,7 @@ app = SnowTyperFactory(
|
|
|
33
33
|
|
|
34
34
|
NameArgument = typer.Argument(help="Name of the object")
|
|
35
35
|
ObjectArgument = typer.Argument(
|
|
36
|
-
help="Type of object. For example table,
|
|
36
|
+
help="Type of object. For example table, database, compute-pool.",
|
|
37
37
|
case_sensitive=False,
|
|
38
38
|
show_default=False,
|
|
39
39
|
)
|
|
@@ -36,16 +36,6 @@ def _get_object_names(object_type: str) -> ObjectNames:
|
|
|
36
36
|
return OBJECT_TO_NAMES[object_type]
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
def _pluralize_object_type(object_type: str) -> str:
|
|
40
|
-
"""
|
|
41
|
-
Pluralize object type without depending on OBJECT_TO_NAMES.
|
|
42
|
-
"""
|
|
43
|
-
if object_type.endswith("y"):
|
|
44
|
-
return object_type[:-1].lower() + "ies"
|
|
45
|
-
else:
|
|
46
|
-
return object_type.lower() + "s"
|
|
47
|
-
|
|
48
|
-
|
|
49
39
|
class ObjectManager(SqlExecutionMixin):
|
|
50
40
|
def show(
|
|
51
41
|
self,
|
|
@@ -85,11 +75,8 @@ class ObjectManager(SqlExecutionMixin):
|
|
|
85
75
|
|
|
86
76
|
def create(self, object_type: str, object_data: Dict[str, Any]) -> str:
|
|
87
77
|
rest = RestApi(self._conn)
|
|
88
|
-
url = rest.determine_url_for_create_query(
|
|
89
|
-
|
|
90
|
-
)
|
|
91
|
-
if not url:
|
|
92
|
-
return f"Create operation for type {object_type} is not supported. Try using `sql -q 'CREATE ...'` command"
|
|
78
|
+
url = rest.determine_url_for_create_query(object_type=object_type)
|
|
79
|
+
|
|
93
80
|
try:
|
|
94
81
|
response = rest.send_rest_request(url=url, method="post", data=object_data)
|
|
95
82
|
# workaround as SnowflakeRestful class ignores some errors, dropping their info and returns {} instead.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
snowflake/cli/__about__.py,sha256=
|
|
1
|
+
snowflake/cli/__about__.py,sha256=hHAuylb0wGYbADN1G-eyVMxlkwOx6WgGwIIu5v9ZVV4,633
|
|
2
2
|
snowflake/cli/__init__.py,sha256=uGA_QRGW3iGwaegpFsLgOhup0zBliBSXh9ou8J439uU,578
|
|
3
3
|
snowflake/cli/api/__init__.py,sha256=kD6lYv5et7QJvW7vzvLN9p2ibfD7pjh9KRWsp2QoYqo,1330
|
|
4
4
|
snowflake/cli/api/cli_global_context.py,sha256=pelnxYpGV6Hg_lTpUC860Xt1c8VFXDS55LL0ockmphc,11410
|
|
5
|
-
snowflake/cli/api/config.py,sha256=
|
|
5
|
+
snowflake/cli/api/config.py,sha256=_dCeNdKhkeF5QQbpBg5s32Xhu2Xa490ixjn9rmCRcxU,10951
|
|
6
6
|
snowflake/cli/api/constants.py,sha256=nVcX-NNZBFUIDX3Gbgm_YKjzv8tgcd1JdYvicV-nL_A,2964
|
|
7
7
|
snowflake/cli/api/exceptions.py,sha256=syNz7HdRVs3hAVC2NUaQINlSo-Ge-WEceuFvLoau2eQ,5118
|
|
8
8
|
snowflake/cli/api/feature_flags.py,sha256=1bBlILOtTn7wSqk0jY3CdwOSCV5lMZF6FxT3HuoYvAI,1418
|
|
9
9
|
snowflake/cli/api/identifiers.py,sha256=_Q53mRIkXCow2mqnXgF7LdMpp-DXvTN8FrKb0rnq8nA,5036
|
|
10
|
-
snowflake/cli/api/rest_api.py,sha256=
|
|
10
|
+
snowflake/cli/api/rest_api.py,sha256=X2hYq-J2mZJmVIEeCUvdk8ccTiV86ltVlj9ac5ZmIak,6070
|
|
11
11
|
snowflake/cli/api/sanitizers.py,sha256=7EKqVQ3KOob0IFFoc_GmXPYpRhgnmIqhnJSvHPgxM5I,1211
|
|
12
12
|
snowflake/cli/api/secure_path.py,sha256=-H2UD1ERc31cCoXyKVQDT0EzjRRLunuOBTfVA49-wc8,13058
|
|
13
13
|
snowflake/cli/api/secure_utils.py,sha256=7fBLtlckmKMPaPRgXfb9XN66tXLX5GdnWw8dL2ZmNKw,1102
|
|
@@ -64,9 +64,9 @@ snowflake/cli/api/utils/rendering.py,sha256=g5Sqc5OsjaRABtU6igFInNbnvpts5PTp4SM4
|
|
|
64
64
|
snowflake/cli/api/utils/types.py,sha256=fVKuls8axKSsBzPqWwrkwkwoXXmedqxNJKqfXrrGyBM,1190
|
|
65
65
|
snowflake/cli/app/__init__.py,sha256=CR_uTgoqHnU1XdyRhm5iQsS86yWXGVx5Ht7aGSDNFmc,765
|
|
66
66
|
snowflake/cli/app/__main__.py,sha256=KrWQBN5trQZUBqC9nQLeQDq134JLkFC0AfmDxRD3U38,833
|
|
67
|
-
snowflake/cli/app/cli_app.py,sha256=
|
|
67
|
+
snowflake/cli/app/cli_app.py,sha256=culZ_65q5eFKR35ScLRNh1z-TbPtJ0-CMVjPjd_ChLs,8149
|
|
68
68
|
snowflake/cli/app/constants.py,sha256=WCqViioXdOt0Cykf-KK42cBLfqHKTfYobMJJ-AC7kSs,698
|
|
69
|
-
snowflake/cli/app/loggers.py,sha256=
|
|
69
|
+
snowflake/cli/app/loggers.py,sha256=tHf5OT-Hj3_LjsZhSphheRwKVc9-pUXuv_BA_6EII8w,6566
|
|
70
70
|
snowflake/cli/app/main_typer.py,sha256=4VQqUCxTGHrc21I2nt-Lel6_T_NS8uwkuAntHjrkx3w,2101
|
|
71
71
|
snowflake/cli/app/printing.py,sha256=H6yclrM5lD55jQ5DXueVBz2bsNyY8UVXwuQ0Aw6ykiA,5322
|
|
72
72
|
snowflake/cli/app/snow_connector.py,sha256=4ZOa7TufXOpnRH5_AKpx6pDcZU8ioz4wo3oE6i3uZhs,8453
|
|
@@ -143,9 +143,9 @@ snowflake/cli/plugins/notebook/plugin_spec.py,sha256=dzmt9GvlDfcFXmM8plhmoQoOtxG
|
|
|
143
143
|
snowflake/cli/plugins/notebook/types.py,sha256=dWXZAsDEzH8iEQPws_w-XTYASynouA1hrHz62zocduw,622
|
|
144
144
|
snowflake/cli/plugins/object/__init__.py,sha256=uGA_QRGW3iGwaegpFsLgOhup0zBliBSXh9ou8J439uU,578
|
|
145
145
|
snowflake/cli/plugins/object/command_aliases.py,sha256=AhInra53zxJDamKWwdWAmJcjH1C6o41CEcvk6QqiPV8,3111
|
|
146
|
-
snowflake/cli/plugins/object/commands.py,sha256=
|
|
146
|
+
snowflake/cli/plugins/object/commands.py,sha256=ok3UIhckd_14b2QaZfKAO-qLjlTbPqFmnQPNFn72H8Y,5769
|
|
147
147
|
snowflake/cli/plugins/object/common.py,sha256=x1V8fiVnh7ohHHq0_NaGFtUvTz0soVRSGm-oCIuhJHs,2608
|
|
148
|
-
snowflake/cli/plugins/object/manager.py,sha256=
|
|
148
|
+
snowflake/cli/plugins/object/manager.py,sha256=Mb_oW85YvyG-EUIPB9sbmNNBE8FAuLnGG-PjBLGwWH0,3871
|
|
149
149
|
snowflake/cli/plugins/object/plugin_spec.py,sha256=nqOiA-qCm2mBGSow4mDvf4A6TKQVwIz5YTGZSxQpr2Q,994
|
|
150
150
|
snowflake/cli/plugins/object_stage_deprecated/__init__.py,sha256=RLQpA97914b74tTgiUft4JM_LvM8zVLWGgDy3Cq2sc8,608
|
|
151
151
|
snowflake/cli/plugins/object_stage_deprecated/commands.py,sha256=_lsUcmu1mYj9HurpLLBpoJspwiEtWbnglXPPTCqGcVk,3835
|
|
@@ -210,8 +210,8 @@ snowflake/cli/templates/default_streamlit/snowflake.yml,sha256=yWFU-vqJ7Z17K3loU
|
|
|
210
210
|
snowflake/cli/templates/default_streamlit/streamlit_app.py,sha256=BtWuwdkgcMiYt21ghyi6Y1b_ITcIunN13ulUknvQbgI,688
|
|
211
211
|
snowflake/cli/templates/default_streamlit/common/hello.py,sha256=3kZSJggAWSYgi06NuI_5USV06mcCOBEzzz2DYeNGpc0,617
|
|
212
212
|
snowflake/cli/templates/default_streamlit/pages/my_page.py,sha256=wj2nMJmpAH_e9hOHoAUxyG4q17vyeVdnBtaXv_5KG24,628
|
|
213
|
-
snowflake_cli_labs-2.6.
|
|
214
|
-
snowflake_cli_labs-2.6.
|
|
215
|
-
snowflake_cli_labs-2.6.
|
|
216
|
-
snowflake_cli_labs-2.6.
|
|
217
|
-
snowflake_cli_labs-2.6.
|
|
213
|
+
snowflake_cli_labs-2.6.1.dist-info/METADATA,sha256=X8DfxpBbg5VTbXdDNDkQ7jwU8QR9MbQHRq1x2wmc7iU,17727
|
|
214
|
+
snowflake_cli_labs-2.6.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
215
|
+
snowflake_cli_labs-2.6.1.dist-info/entry_points.txt,sha256=_qdnT44fYFbH78kb6Em5jr2_26amIg3UIAvSdmqT6TY,57
|
|
216
|
+
snowflake_cli_labs-2.6.1.dist-info/licenses/LICENSE,sha256=mJMA3Uz2AbjU_kVggo1CAx01XhBsI7BSi2H7ggUg_-c,11344
|
|
217
|
+
snowflake_cli_labs-2.6.1.dist-info/RECORD,,
|
|
File without changes
|
{snowflake_cli_labs-2.6.0rc0.dist-info → snowflake_cli_labs-2.6.1.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{snowflake_cli_labs-2.6.0rc0.dist-info → snowflake_cli_labs-2.6.1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|