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,332 +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 sys
|
|
18
|
-
from pathlib import Path
|
|
19
|
-
from typing import List, Optional
|
|
20
|
-
|
|
21
|
-
import click
|
|
22
|
-
import typer
|
|
23
|
-
from click import UsageError
|
|
24
|
-
from snowflake.cli._plugins.cortex.constants import DEFAULT_MODEL
|
|
25
|
-
from snowflake.cli._plugins.cortex.manager import CortexManager
|
|
26
|
-
from snowflake.cli._plugins.cortex.types import (
|
|
27
|
-
Language,
|
|
28
|
-
Model,
|
|
29
|
-
Question,
|
|
30
|
-
SourceDocument,
|
|
31
|
-
Text,
|
|
32
|
-
)
|
|
33
|
-
from snowflake.cli.api.cli_global_context import get_cli_context
|
|
34
|
-
from snowflake.cli.api.commands.overrideable_parameter import (
|
|
35
|
-
OverrideableArgument,
|
|
36
|
-
OverrideableOption,
|
|
37
|
-
)
|
|
38
|
-
from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
|
|
39
|
-
from snowflake.cli.api.constants import PYTHON_3_12
|
|
40
|
-
from snowflake.cli.api.output.types import (
|
|
41
|
-
CollectionResult,
|
|
42
|
-
CommandResult,
|
|
43
|
-
MessageResult,
|
|
44
|
-
)
|
|
45
|
-
from snowflake.cli.api.secure_path import SecurePath
|
|
46
|
-
|
|
47
|
-
app = SnowTyperFactory(
|
|
48
|
-
name="cortex",
|
|
49
|
-
help="Provides access to Snowflake Cortex.",
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
SEARCH_COMMAND_ENABLED = sys.version_info < PYTHON_3_12
|
|
53
|
-
|
|
54
|
-
SOURCE_EXCLUSIVE_OPTION_NAMES = ["text", "file", "source_document_text"]
|
|
55
|
-
|
|
56
|
-
# Creates a Typer option and verifies if the mutually exclusive options are set in the command.
|
|
57
|
-
ExclusiveReadableFileOption = OverrideableOption(
|
|
58
|
-
None,
|
|
59
|
-
"--file",
|
|
60
|
-
mutually_exclusive=SOURCE_EXCLUSIVE_OPTION_NAMES,
|
|
61
|
-
exists=True,
|
|
62
|
-
file_okay=True,
|
|
63
|
-
dir_okay=False,
|
|
64
|
-
readable=True,
|
|
65
|
-
show_default=False,
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
# Creates a Typer argument and verifies if the mutually exclusive options are set in the command.
|
|
69
|
-
ExclusiveTextSourceArgument = OverrideableArgument(
|
|
70
|
-
mutually_exclusive=SOURCE_EXCLUSIVE_OPTION_NAMES,
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
@app.command(
|
|
75
|
-
requires_connection=True,
|
|
76
|
-
hidden=not SEARCH_COMMAND_ENABLED,
|
|
77
|
-
)
|
|
78
|
-
def search(
|
|
79
|
-
query: str = typer.Argument(help="The search query string"),
|
|
80
|
-
service: str = typer.Option(
|
|
81
|
-
help="Cortex search service to be used. Example: --service my_cortex_service",
|
|
82
|
-
),
|
|
83
|
-
columns: Optional[List[str]] = typer.Option(
|
|
84
|
-
help='Columns that will be returned with the results. If none is provided, only search column will be included in results. Example --columns "foo" --columns "bar"',
|
|
85
|
-
default=None,
|
|
86
|
-
),
|
|
87
|
-
limit: int = typer.Option(help="Maximum number of results retrieved", default=1),
|
|
88
|
-
**options,
|
|
89
|
-
):
|
|
90
|
-
"""
|
|
91
|
-
Performs query search using Cortex Search Services.
|
|
92
|
-
"""
|
|
93
|
-
|
|
94
|
-
if not SEARCH_COMMAND_ENABLED:
|
|
95
|
-
raise click.ClickException(
|
|
96
|
-
"Cortex Search uses Snowflake Python API that currently does not support your Python version"
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
from snowflake.core import Root
|
|
100
|
-
|
|
101
|
-
if not columns:
|
|
102
|
-
columns = []
|
|
103
|
-
|
|
104
|
-
conn = get_cli_context().connection
|
|
105
|
-
|
|
106
|
-
search_service = (
|
|
107
|
-
Root(conn)
|
|
108
|
-
.databases[conn.database]
|
|
109
|
-
.schemas[conn.schema]
|
|
110
|
-
.cortex_search_services[service]
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
response = search_service.search(
|
|
114
|
-
query=query, columns=columns, limit=limit, filter={}
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
return CollectionResult(response.results)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
@app.command(
|
|
121
|
-
name="complete",
|
|
122
|
-
requires_connection=True,
|
|
123
|
-
)
|
|
124
|
-
def complete(
|
|
125
|
-
text: Optional[str] = ExclusiveTextSourceArgument(
|
|
126
|
-
default=None,
|
|
127
|
-
help="Prompt to be used to generate a completion. Cannot be combined with --file option.",
|
|
128
|
-
show_default=False,
|
|
129
|
-
),
|
|
130
|
-
model: Optional[str] = typer.Option(
|
|
131
|
-
DEFAULT_MODEL,
|
|
132
|
-
"--model",
|
|
133
|
-
help="String specifying the model to be used.",
|
|
134
|
-
),
|
|
135
|
-
file: Optional[Path] = ExclusiveReadableFileOption(
|
|
136
|
-
help="JSON file containing conversation history to be used to generate a completion. Cannot be combined with TEXT argument.",
|
|
137
|
-
),
|
|
138
|
-
**options,
|
|
139
|
-
) -> CommandResult:
|
|
140
|
-
"""
|
|
141
|
-
Given a prompt, the command generates a response using your choice of language model.
|
|
142
|
-
In the simplest use case, the prompt is a single string.
|
|
143
|
-
You may also provide a JSON file with conversation history including multiple prompts and responses for interactive chat-style usage.
|
|
144
|
-
"""
|
|
145
|
-
|
|
146
|
-
manager = CortexManager()
|
|
147
|
-
|
|
148
|
-
if text:
|
|
149
|
-
result_text = manager.complete_for_prompt(
|
|
150
|
-
text=Text(text),
|
|
151
|
-
model=Model(model),
|
|
152
|
-
)
|
|
153
|
-
elif file:
|
|
154
|
-
result_text = manager.complete_for_conversation(
|
|
155
|
-
conversation_json_file=SecurePath(file),
|
|
156
|
-
model=Model(model),
|
|
157
|
-
)
|
|
158
|
-
else:
|
|
159
|
-
raise UsageError("Either --file option or TEXT argument has to be provided.")
|
|
160
|
-
|
|
161
|
-
return MessageResult(result_text.strip())
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
@app.command(
|
|
165
|
-
name="extract-answer",
|
|
166
|
-
requires_connection=True,
|
|
167
|
-
)
|
|
168
|
-
def extract_answer(
|
|
169
|
-
question: str = typer.Argument(
|
|
170
|
-
None,
|
|
171
|
-
help="String containing the question to be answered.",
|
|
172
|
-
show_default=False,
|
|
173
|
-
),
|
|
174
|
-
source_document_text: Optional[str] = ExclusiveTextSourceArgument(
|
|
175
|
-
default=None,
|
|
176
|
-
help="String containing the plain-text or JSON document that contains the answer to the question. Cannot be combined with --file option.",
|
|
177
|
-
show_default=False,
|
|
178
|
-
),
|
|
179
|
-
file: Optional[Path] = ExclusiveReadableFileOption(
|
|
180
|
-
help="File containing the plain-text or JSON document that contains the answer to the question. Cannot be combined with SOURCE_DOCUMENT_TEXT argument.",
|
|
181
|
-
),
|
|
182
|
-
**options,
|
|
183
|
-
) -> CommandResult:
|
|
184
|
-
"""
|
|
185
|
-
Extracts an answer to a given question from a text document.
|
|
186
|
-
The document may be a plain-English document or a string representation of a semi-structured (JSON) data object.
|
|
187
|
-
"""
|
|
188
|
-
|
|
189
|
-
manager = CortexManager()
|
|
190
|
-
|
|
191
|
-
if source_document_text:
|
|
192
|
-
result_text = manager.extract_answer_from_source_document(
|
|
193
|
-
source_document=SourceDocument(source_document_text),
|
|
194
|
-
question=Question(question),
|
|
195
|
-
)
|
|
196
|
-
elif file:
|
|
197
|
-
result_text = manager.extract_answer_from_source_document_file(
|
|
198
|
-
source_document_input_file=SecurePath(file),
|
|
199
|
-
question=Question(question),
|
|
200
|
-
)
|
|
201
|
-
else:
|
|
202
|
-
raise UsageError(
|
|
203
|
-
"Either --file option or SOURCE_DOCUMENT_TEXT argument has to be provided."
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
return MessageResult(result_text.strip())
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
@app.command(
|
|
210
|
-
name="sentiment",
|
|
211
|
-
requires_connection=True,
|
|
212
|
-
)
|
|
213
|
-
def sentiment(
|
|
214
|
-
text: Optional[str] = ExclusiveTextSourceArgument(
|
|
215
|
-
default=None,
|
|
216
|
-
help="String containing the text for which a sentiment score should be calculated. Cannot be combined with --file option.",
|
|
217
|
-
show_default=False,
|
|
218
|
-
),
|
|
219
|
-
file: Optional[Path] = ExclusiveReadableFileOption(
|
|
220
|
-
help="File containing the text for which a sentiment score should be calculated. Cannot be combined with TEXT argument.",
|
|
221
|
-
),
|
|
222
|
-
**options,
|
|
223
|
-
) -> CommandResult:
|
|
224
|
-
"""
|
|
225
|
-
Returns sentiment as a score between -1 to 1
|
|
226
|
-
(with -1 being the most negative and 1 the most positive,
|
|
227
|
-
with values around 0 neutral) for the given English-language input text.
|
|
228
|
-
"""
|
|
229
|
-
|
|
230
|
-
manager = CortexManager()
|
|
231
|
-
|
|
232
|
-
if text:
|
|
233
|
-
result_text = manager.calculate_sentiment_for_text(
|
|
234
|
-
text=Text(text),
|
|
235
|
-
)
|
|
236
|
-
elif file:
|
|
237
|
-
result_text = manager.calculate_sentiment_for_text_file(
|
|
238
|
-
text_file=SecurePath(file),
|
|
239
|
-
)
|
|
240
|
-
else:
|
|
241
|
-
raise UsageError("Either --file option or TEXT argument has to be provided.")
|
|
242
|
-
|
|
243
|
-
return MessageResult(result_text.strip())
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
@app.command(
|
|
247
|
-
name="summarize",
|
|
248
|
-
requires_connection=True,
|
|
249
|
-
)
|
|
250
|
-
def summarize(
|
|
251
|
-
text: Optional[str] = ExclusiveTextSourceArgument(
|
|
252
|
-
default=None,
|
|
253
|
-
help="String containing the English text from which a summary should be generated. Cannot be combined with --file option.",
|
|
254
|
-
show_default=False,
|
|
255
|
-
),
|
|
256
|
-
file: Optional[Path] = ExclusiveReadableFileOption(
|
|
257
|
-
help="File containing the English text from which a summary should be generated. Cannot be combined with TEXT argument.",
|
|
258
|
-
),
|
|
259
|
-
**options,
|
|
260
|
-
) -> CommandResult:
|
|
261
|
-
"""
|
|
262
|
-
Summarizes the given English-language input text.
|
|
263
|
-
"""
|
|
264
|
-
|
|
265
|
-
manager = CortexManager()
|
|
266
|
-
|
|
267
|
-
if text:
|
|
268
|
-
result_text = manager.summarize_text(
|
|
269
|
-
text=Text(text),
|
|
270
|
-
)
|
|
271
|
-
elif file:
|
|
272
|
-
result_text = manager.summarize_text_file(
|
|
273
|
-
text_file=SecurePath(file),
|
|
274
|
-
)
|
|
275
|
-
else:
|
|
276
|
-
raise UsageError("Either --file option or TEXT argument has to be provided.")
|
|
277
|
-
|
|
278
|
-
return MessageResult(result_text.strip())
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
@app.command(
|
|
282
|
-
name="translate",
|
|
283
|
-
requires_connection=True,
|
|
284
|
-
)
|
|
285
|
-
def translate(
|
|
286
|
-
text: Optional[str] = ExclusiveTextSourceArgument(
|
|
287
|
-
default=None,
|
|
288
|
-
help="String containing the text to be translated. Cannot be combined with --file option.",
|
|
289
|
-
show_default=False,
|
|
290
|
-
),
|
|
291
|
-
from_language: Optional[str] = typer.Option(
|
|
292
|
-
None,
|
|
293
|
-
"--from",
|
|
294
|
-
help="String specifying the language code for the language the text is currently in. See Snowflake Cortex documentation for a list of supported language codes.",
|
|
295
|
-
show_default=False,
|
|
296
|
-
),
|
|
297
|
-
to_language: str = typer.Option(
|
|
298
|
-
...,
|
|
299
|
-
"--to",
|
|
300
|
-
help="String specifying the language code into which the text should be translated. See Snowflake Cortex documentation for a list of supported language codes.",
|
|
301
|
-
show_default=False,
|
|
302
|
-
),
|
|
303
|
-
file: Optional[Path] = ExclusiveReadableFileOption(
|
|
304
|
-
help="File containing the text to be translated. Cannot be combined with TEXT argument.",
|
|
305
|
-
),
|
|
306
|
-
**options,
|
|
307
|
-
) -> CommandResult:
|
|
308
|
-
"""
|
|
309
|
-
Translates text from the indicated or detected source language to a target language.
|
|
310
|
-
"""
|
|
311
|
-
|
|
312
|
-
manager = CortexManager()
|
|
313
|
-
|
|
314
|
-
source_language = None if from_language is None else Language(from_language)
|
|
315
|
-
target_language = Language(to_language)
|
|
316
|
-
|
|
317
|
-
if text:
|
|
318
|
-
result_text = manager.translate_text(
|
|
319
|
-
text=Text(text),
|
|
320
|
-
source_language=source_language,
|
|
321
|
-
target_language=target_language,
|
|
322
|
-
)
|
|
323
|
-
elif file:
|
|
324
|
-
result_text = manager.translate_text_file(
|
|
325
|
-
text_file=SecurePath(file),
|
|
326
|
-
source_language=source_language,
|
|
327
|
-
target_language=target_language,
|
|
328
|
-
)
|
|
329
|
-
else:
|
|
330
|
-
raise UsageError("Either --file option or TEXT argument has to be provided.")
|
|
331
|
-
|
|
332
|
-
return MessageResult(result_text.strip())
|
|
@@ -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._plugins.cortex.types import Model
|
|
16
|
-
|
|
17
|
-
DEFAULT_MODEL: Model = Model("snowflake-arctic")
|
|
@@ -1,189 +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 json
|
|
18
|
-
import logging
|
|
19
|
-
from typing import Callable, Optional
|
|
20
|
-
|
|
21
|
-
from click import ClickException
|
|
22
|
-
from snowflake.cli._plugins.cortex.types import (
|
|
23
|
-
Language,
|
|
24
|
-
Model,
|
|
25
|
-
Question,
|
|
26
|
-
SourceDocument,
|
|
27
|
-
Text,
|
|
28
|
-
)
|
|
29
|
-
from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB
|
|
30
|
-
from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
|
|
31
|
-
from snowflake.cli.api.secure_path import SecurePath
|
|
32
|
-
from snowflake.cli.api.sql_execution import SqlExecutionMixin
|
|
33
|
-
from snowflake.connector import ProgrammingError
|
|
34
|
-
from snowflake.connector.cursor import DictCursor
|
|
35
|
-
|
|
36
|
-
log = logging.getLogger(__name__)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class CortexManager(SqlExecutionMixin):
|
|
40
|
-
def complete_for_prompt(
|
|
41
|
-
self,
|
|
42
|
-
text: Text,
|
|
43
|
-
model: Model,
|
|
44
|
-
) -> str:
|
|
45
|
-
query = f"""\
|
|
46
|
-
SELECT SNOWFLAKE.CORTEX.COMPLETE(
|
|
47
|
-
'{model}',
|
|
48
|
-
'{self._escape_input(text)}'
|
|
49
|
-
) AS CORTEX_RESULT;"""
|
|
50
|
-
return self._query_cortex_result_str(query)
|
|
51
|
-
|
|
52
|
-
def complete_for_conversation(
|
|
53
|
-
self,
|
|
54
|
-
conversation_json_file: SecurePath,
|
|
55
|
-
model: Model,
|
|
56
|
-
) -> str:
|
|
57
|
-
json_content = conversation_json_file.read_text(
|
|
58
|
-
file_size_limit_mb=DEFAULT_SIZE_LIMIT_MB
|
|
59
|
-
)
|
|
60
|
-
query = f"""\
|
|
61
|
-
SELECT SNOWFLAKE.CORTEX.COMPLETE(
|
|
62
|
-
'{model}',
|
|
63
|
-
PARSE_JSON('{self._escape_input(json_content)}'),
|
|
64
|
-
{{}}
|
|
65
|
-
) AS CORTEX_RESULT;"""
|
|
66
|
-
raw_result = self._query_cortex_result_str(query)
|
|
67
|
-
json_result = json.loads(raw_result)
|
|
68
|
-
return self._extract_text_result_from_json_result(
|
|
69
|
-
lambda: json_result["choices"][0]["messages"]
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
def extract_answer_from_source_document(
|
|
73
|
-
self,
|
|
74
|
-
source_document: SourceDocument,
|
|
75
|
-
question: Question,
|
|
76
|
-
) -> str:
|
|
77
|
-
query = f"""\
|
|
78
|
-
SELECT SNOWFLAKE.CORTEX.EXTRACT_ANSWER(
|
|
79
|
-
'{self._escape_input(source_document)}',
|
|
80
|
-
'{self._escape_input(question)}'
|
|
81
|
-
) AS CORTEX_RESULT;"""
|
|
82
|
-
raw_result = self._query_cortex_result_str(query)
|
|
83
|
-
json_result = json.loads(raw_result)
|
|
84
|
-
return self._extract_text_result_from_json_result(
|
|
85
|
-
lambda: json_result[0]["answer"]
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
def extract_answer_from_source_document_file(
|
|
89
|
-
self,
|
|
90
|
-
source_document_input_file: SecurePath,
|
|
91
|
-
question: Question,
|
|
92
|
-
) -> str:
|
|
93
|
-
source_document_content = source_document_input_file.read_text(
|
|
94
|
-
file_size_limit_mb=DEFAULT_SIZE_LIMIT_MB
|
|
95
|
-
)
|
|
96
|
-
return self.extract_answer_from_source_document(
|
|
97
|
-
source_document=SourceDocument(source_document_content), question=question
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
def calculate_sentiment_for_text(
|
|
101
|
-
self,
|
|
102
|
-
text: Text,
|
|
103
|
-
) -> str:
|
|
104
|
-
query = f"""\
|
|
105
|
-
SELECT SNOWFLAKE.CORTEX.SENTIMENT(
|
|
106
|
-
'{self._escape_input(text)}'
|
|
107
|
-
) AS CORTEX_RESULT;"""
|
|
108
|
-
return self._query_cortex_result_str(query)
|
|
109
|
-
|
|
110
|
-
def calculate_sentiment_for_text_file(
|
|
111
|
-
self,
|
|
112
|
-
text_file: SecurePath,
|
|
113
|
-
) -> str:
|
|
114
|
-
file_content = text_file.read_text(file_size_limit_mb=DEFAULT_SIZE_LIMIT_MB)
|
|
115
|
-
return self.calculate_sentiment_for_text(
|
|
116
|
-
text=Text(file_content),
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
def summarize_text(
|
|
120
|
-
self,
|
|
121
|
-
text: Text,
|
|
122
|
-
) -> str:
|
|
123
|
-
query = f"""\
|
|
124
|
-
SELECT SNOWFLAKE.CORTEX.SUMMARIZE(
|
|
125
|
-
'{self._escape_input(text)}'
|
|
126
|
-
) AS CORTEX_RESULT;"""
|
|
127
|
-
return self._query_cortex_result_str(query)
|
|
128
|
-
|
|
129
|
-
def summarize_text_file(
|
|
130
|
-
self,
|
|
131
|
-
text_file: SecurePath,
|
|
132
|
-
) -> str:
|
|
133
|
-
file_content = text_file.read_text(file_size_limit_mb=DEFAULT_SIZE_LIMIT_MB)
|
|
134
|
-
return self.summarize_text(
|
|
135
|
-
text=Text(file_content),
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
def translate_text(
|
|
139
|
-
self,
|
|
140
|
-
text: Text,
|
|
141
|
-
source_language: Optional[Language],
|
|
142
|
-
target_language: Language,
|
|
143
|
-
) -> str:
|
|
144
|
-
query = f"""\
|
|
145
|
-
SELECT SNOWFLAKE.CORTEX.TRANSLATE(
|
|
146
|
-
'{self._escape_input(text)}',
|
|
147
|
-
'{source_language or ""}',
|
|
148
|
-
'{target_language}'
|
|
149
|
-
) AS CORTEX_RESULT;"""
|
|
150
|
-
return self._query_cortex_result_str(query)
|
|
151
|
-
|
|
152
|
-
def translate_text_file(
|
|
153
|
-
self,
|
|
154
|
-
text_file: SecurePath,
|
|
155
|
-
source_language: Optional[Language],
|
|
156
|
-
target_language: Language,
|
|
157
|
-
) -> str:
|
|
158
|
-
file_content = text_file.read_text(file_size_limit_mb=DEFAULT_SIZE_LIMIT_MB)
|
|
159
|
-
return self.translate_text(
|
|
160
|
-
text=Text(file_content),
|
|
161
|
-
source_language=source_language,
|
|
162
|
-
target_language=target_language,
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
@staticmethod
|
|
166
|
-
def _escape_input(plain_input: str):
|
|
167
|
-
# escape backslashes to not escape too much, this replace has to be the first one
|
|
168
|
-
# escape single quotes because they are wrapping the whole string in SQL
|
|
169
|
-
return plain_input.replace("\\", "\\\\").replace("'", "\\'")
|
|
170
|
-
|
|
171
|
-
@staticmethod
|
|
172
|
-
def _extract_text_result_from_json_result(
|
|
173
|
-
extract_function: Callable[[], str]
|
|
174
|
-
) -> str:
|
|
175
|
-
try:
|
|
176
|
-
return extract_function()
|
|
177
|
-
except (KeyError, IndexError) as ex:
|
|
178
|
-
log.debug("Cannot find Cortex result message in a response", exc_info=ex)
|
|
179
|
-
raise ClickException("Unexpected format of response from Snowflake")
|
|
180
|
-
|
|
181
|
-
def _query_cortex_result_str(self, query: str) -> str:
|
|
182
|
-
try:
|
|
183
|
-
cursor = self._execute_query(query, cursor_class=DictCursor)
|
|
184
|
-
if cursor.rowcount is None:
|
|
185
|
-
raise SnowflakeSQLExecutionError(query)
|
|
186
|
-
return str(cursor.fetchone()["CORTEX_RESULT"])
|
|
187
|
-
except ProgrammingError as ex:
|
|
188
|
-
log.debug("ProgrammingError occurred during SQL execution", exc_info=ex)
|
|
189
|
-
raise ClickException(str(ex))
|
|
@@ -1,30 +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._plugins.cortex import commands
|
|
16
|
-
from snowflake.cli.api.plugins.command import (
|
|
17
|
-
SNOWCLI_ROOT_COMMAND_PATH,
|
|
18
|
-
CommandSpec,
|
|
19
|
-
CommandType,
|
|
20
|
-
plugin_hook_impl,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
@plugin_hook_impl
|
|
25
|
-
def command_spec():
|
|
26
|
-
return CommandSpec(
|
|
27
|
-
parent_command_path=SNOWCLI_ROOT_COMMAND_PATH,
|
|
28
|
-
command_type=CommandType.COMMAND_GROUP,
|
|
29
|
-
typer_instance=commands.app.create_instance(),
|
|
30
|
-
)
|
|
@@ -1,22 +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 typing import NewType
|
|
16
|
-
|
|
17
|
-
Text = NewType("Text", str)
|
|
18
|
-
Model = NewType("Model", str)
|
|
19
|
-
Language = NewType("Language", str)
|
|
20
|
-
InputString = NewType("InputString", str)
|
|
21
|
-
Question = NewType("Question", str)
|
|
22
|
-
SourceDocument = NewType("SourceDocument", str)
|
|
@@ -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.
|