snowflake-cli-labs 2.8.0rc1__py3-none-any.whl → 2.8.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-2.8.0rc1.dist-info → snowflake_cli_labs-2.8.2.dist-info}/METADATA +7 -95
- snowflake_cli_labs-2.8.2.dist-info/RECORD +5 -0
- snowflake/cli/__about__.py +0 -17
- snowflake/cli/__init__.py +0 -13
- snowflake/cli/api/__init__.py +0 -48
- snowflake/cli/api/cli_global_context.py +0 -390
- snowflake/cli/api/commands/__init__.py +0 -13
- snowflake/cli/api/commands/alias.py +0 -23
- snowflake/cli/api/commands/decorators.py +0 -354
- snowflake/cli/api/commands/execution_metadata.py +0 -40
- snowflake/cli/api/commands/experimental_behaviour.py +0 -19
- snowflake/cli/api/commands/flags.py +0 -640
- snowflake/cli/api/commands/project_initialisation.py +0 -65
- snowflake/cli/api/commands/snow_typer.py +0 -237
- snowflake/cli/api/commands/typer_pre_execute.py +0 -26
- snowflake/cli/api/config.py +0 -348
- snowflake/cli/api/console/__init__.py +0 -17
- snowflake/cli/api/console/abc.py +0 -89
- snowflake/cli/api/console/console.py +0 -134
- snowflake/cli/api/console/enum.py +0 -17
- snowflake/cli/api/constants.py +0 -79
- snowflake/cli/api/errno.py +0 -27
- snowflake/cli/api/exceptions.py +0 -164
- snowflake/cli/api/feature_flags.py +0 -55
- snowflake/cli/api/identifiers.py +0 -154
- 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 -84
- snowflake/cli/api/project/definition_manager.py +0 -134
- 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/application_entity.py +0 -44
- snowflake/cli/api/project/schemas/entities/application_package_entity.py +0 -66
- snowflake/cli/api/project/schemas/entities/common.py +0 -78
- snowflake/cli/api/project/schemas/entities/entities.py +0 -30
- snowflake/cli/api/project/schemas/identifier_model.py +0 -49
- snowflake/cli/api/project/schemas/native_app/__init__.py +0 -13
- snowflake/cli/api/project/schemas/native_app/application.py +0 -62
- snowflake/cli/api/project/schemas/native_app/native_app.py +0 -93
- snowflake/cli/api/project/schemas/native_app/package.py +0 -78
- snowflake/cli/api/project/schemas/native_app/path_mapping.py +0 -65
- snowflake/cli/api/project/schemas/project_definition.py +0 -199
- snowflake/cli/api/project/schemas/snowpark/__init__.py +0 -13
- snowflake/cli/api/project/schemas/snowpark/argument.py +0 -28
- snowflake/cli/api/project/schemas/snowpark/callable.py +0 -69
- snowflake/cli/api/project/schemas/snowpark/snowpark.py +0 -36
- snowflake/cli/api/project/schemas/streamlit/__init__.py +0 -13
- snowflake/cli/api/project/schemas/streamlit/streamlit.py +0 -46
- snowflake/cli/api/project/schemas/template.py +0 -77
- snowflake/cli/api/project/schemas/updatable_model.py +0 -194
- snowflake/cli/api/project/util.py +0 -261
- snowflake/cli/api/rendering/__init__.py +0 -13
- snowflake/cli/api/rendering/jinja.py +0 -112
- snowflake/cli/api/rendering/project_definition_templates.py +0 -39
- snowflake/cli/api/rendering/project_templates.py +0 -98
- snowflake/cli/api/rendering/sql_templates.py +0 -60
- snowflake/cli/api/rest_api.py +0 -172
- snowflake/cli/api/sanitizers.py +0 -43
- snowflake/cli/api/secure_path.py +0 -362
- snowflake/cli/api/secure_utils.py +0 -29
- snowflake/cli/api/sql_execution.py +0 -260
- snowflake/cli/api/utils/__init__.py +0 -13
- snowflake/cli/api/utils/cursor.py +0 -34
- snowflake/cli/api/utils/definition_rendering.py +0 -383
- 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/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/build_and_push.sh +0 -8
- snowflake/cli/app/cli_app.py +0 -243
- snowflake/cli/app/commands_registration/__init__.py +0 -33
- snowflake/cli/app/commands_registration/builtin_plugins.py +0 -54
- 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 -100
- 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 -57
- 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/snow_connector.py +0 -243
- snowflake/cli/app/telemetry.py +0 -189
- snowflake/cli/plugins/__init__.py +0 -13
- snowflake/cli/plugins/connection/__init__.py +0 -13
- snowflake/cli/plugins/connection/commands.py +0 -330
- snowflake/cli/plugins/connection/plugin_spec.py +0 -30
- snowflake/cli/plugins/connection/util.py +0 -179
- snowflake/cli/plugins/cortex/__init__.py +0 -13
- snowflake/cli/plugins/cortex/commands.py +0 -327
- 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 -305
- snowflake/cli/plugins/git/manager.py +0 -96
- snowflake/cli/plugins/git/plugin_spec.py +0 -30
- snowflake/cli/plugins/init/__init__.py +0 -13
- snowflake/cli/plugins/init/commands.py +0 -244
- snowflake/cli/plugins/init/plugin_spec.py +0 -30
- snowflake/cli/plugins/nativeapp/__init__.py +0 -13
- snowflake/cli/plugins/nativeapp/artifacts.py +0 -742
- 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 -130
- snowflake/cli/plugins/nativeapp/codegen/sandbox.py +0 -306
- snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -172
- snowflake/cli/plugins/nativeapp/codegen/setup/setup_driver.py.source +0 -56
- 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 -528
- snowflake/cli/plugins/nativeapp/commands.py +0 -439
- snowflake/cli/plugins/nativeapp/common_flags.py +0 -44
- snowflake/cli/plugins/nativeapp/constants.py +0 -27
- snowflake/cli/plugins/nativeapp/exceptions.py +0 -122
- snowflake/cli/plugins/nativeapp/feature_flags.py +0 -24
- snowflake/cli/plugins/nativeapp/init.py +0 -345
- snowflake/cli/plugins/nativeapp/manager.py +0 -823
- snowflake/cli/plugins/nativeapp/plugin_spec.py +0 -30
- snowflake/cli/plugins/nativeapp/policy.py +0 -50
- snowflake/cli/plugins/nativeapp/project_model.py +0 -195
- snowflake/cli/plugins/nativeapp/run_processor.py +0 -389
- snowflake/cli/plugins/nativeapp/teardown_processor.py +0 -301
- snowflake/cli/plugins/nativeapp/utils.py +0 -98
- snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +0 -135
- snowflake/cli/plugins/nativeapp/version/__init__.py +0 -13
- snowflake/cli/plugins/nativeapp/version/commands.py +0 -170
- snowflake/cli/plugins/nativeapp/version/version_processor.py +0 -362
- snowflake/cli/plugins/notebook/__init__.py +0 -13
- snowflake/cli/plugins/notebook/commands.py +0 -84
- 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 -16
- snowflake/cli/plugins/object/__init__.py +0 -13
- snowflake/cli/plugins/object/command_aliases.py +0 -94
- snowflake/cli/plugins/object/commands.py +0 -174
- snowflake/cli/plugins/object/common.py +0 -85
- snowflake/cli/plugins/object/manager.py +0 -96
- snowflake/cli/plugins/object/plugin_spec.py +0 -30
- snowflake/cli/plugins/object_stage_deprecated/__init__.py +0 -15
- snowflake/cli/plugins/object_stage_deprecated/commands.py +0 -122
- snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +0 -32
- snowflake/cli/plugins/snowpark/__init__.py +0 -13
- snowflake/cli/plugins/snowpark/commands.py +0 -548
- snowflake/cli/plugins/snowpark/common.py +0 -307
- snowflake/cli/plugins/snowpark/manager.py +0 -109
- snowflake/cli/plugins/snowpark/models.py +0 -156
- snowflake/cli/plugins/snowpark/package/__init__.py +0 -13
- snowflake/cli/plugins/snowpark/package/anaconda_packages.py +0 -233
- snowflake/cli/plugins/snowpark/package/commands.py +0 -256
- snowflake/cli/plugins/snowpark/package/manager.py +0 -43
- 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_package_paths.py +0 -65
- snowflake/cli/plugins/snowpark/snowpark_shared.py +0 -95
- snowflake/cli/plugins/snowpark/zipper.py +0 -81
- snowflake/cli/plugins/spcs/__init__.py +0 -35
- 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 -240
- 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 -196
- snowflake/cli/plugins/spcs/image_repository/manager.py +0 -84
- snowflake/cli/plugins/spcs/jobs/__init__.py +0 -13
- snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
- snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
- 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 -311
- snowflake/cli/plugins/spcs/services/manager.py +0 -170
- snowflake/cli/plugins/sql/__init__.py +0 -13
- snowflake/cli/plugins/sql/commands.py +0 -83
- 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 -261
- snowflake/cli/plugins/stage/diff.py +0 -326
- snowflake/cli/plugins/stage/manager.py +0 -544
- snowflake/cli/plugins/stage/md5.py +0 -160
- snowflake/cli/plugins/stage/plugin_spec.py +0 -30
- snowflake/cli/plugins/streamlit/__init__.py +0 -13
- snowflake/cli/plugins/streamlit/commands.py +0 -186
- snowflake/cli/plugins/streamlit/manager.py +0 -222
- snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
- snowflake/cli/plugins/workspace/__init__.py +0 -13
- snowflake/cli/plugins/workspace/commands.py +0 -35
- snowflake/cli/plugins/workspace/plugin_spec.py +0 -30
- snowflake/cli/templates/default_snowpark/.gitignore +0 -4
- snowflake/cli/templates/default_snowpark/app/__init__.py +0 -0
- snowflake/cli/templates/default_snowpark/app/common.py +0 -2
- snowflake/cli/templates/default_snowpark/app/functions.py +0 -15
- snowflake/cli/templates/default_snowpark/app/procedures.py +0 -22
- snowflake/cli/templates/default_snowpark/requirements.txt +0 -1
- snowflake/cli/templates/default_snowpark/snowflake.yml +0 -23
- snowflake/cli/templates/default_streamlit/.gitignore +0 -4
- snowflake/cli/templates/default_streamlit/common/hello.py +0 -2
- snowflake/cli/templates/default_streamlit/environment.yml +0 -6
- snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -3
- snowflake/cli/templates/default_streamlit/snowflake.yml +0 -10
- snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -4
- snowflake_cli_labs-2.8.0rc1.dist-info/RECORD +0 -240
- snowflake_cli_labs-2.8.0rc1.dist-info/entry_points.txt +0 -2
- {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-2.8.2.dist-info}/WHEEL +0 -0
- {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-2.8.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from __future__ import annotations
|
|
16
|
-
|
|
17
|
-
import logging
|
|
18
|
-
from dataclasses import dataclass
|
|
19
|
-
from typing import Dict, List, Set
|
|
20
|
-
|
|
21
|
-
import requests
|
|
22
|
-
from click import ClickException
|
|
23
|
-
from packaging.requirements import InvalidRequirement
|
|
24
|
-
from packaging.requirements import Requirement as PkgRequirement
|
|
25
|
-
from packaging.version import InvalidVersion, parse
|
|
26
|
-
from requests import HTTPError
|
|
27
|
-
from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
|
|
28
|
-
from snowflake.cli.api.secure_path import SecurePath
|
|
29
|
-
from snowflake.cli.api.sql_execution import SqlExecutionMixin
|
|
30
|
-
from snowflake.cli.plugins.snowpark.models import Requirement
|
|
31
|
-
from snowflake.connector import DictCursor
|
|
32
|
-
|
|
33
|
-
log = logging.getLogger(__name__)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
@dataclass
|
|
37
|
-
class FilterRequirementsResult:
|
|
38
|
-
"""A dataclass to hold the results of parsing requirements files and dividing them into
|
|
39
|
-
snowflake-supported vs other packages.
|
|
40
|
-
"""
|
|
41
|
-
|
|
42
|
-
in_snowflake: List[Requirement]
|
|
43
|
-
unavailable: List[Requirement]
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
@dataclass
|
|
47
|
-
class AvailablePackage:
|
|
48
|
-
snowflake_name: str
|
|
49
|
-
versions: Set[str]
|
|
50
|
-
|
|
51
|
-
def iter_versions(self):
|
|
52
|
-
for version in self.versions:
|
|
53
|
-
yield parse(version)
|
|
54
|
-
|
|
55
|
-
def is_required_version_available(self, requirement: Requirement) -> bool:
|
|
56
|
-
try:
|
|
57
|
-
package_specifiers = PkgRequirement(requirement.line).specifier
|
|
58
|
-
return any(
|
|
59
|
-
version in package_specifiers for version in self.iter_versions()
|
|
60
|
-
)
|
|
61
|
-
except (InvalidVersion, InvalidRequirement):
|
|
62
|
-
# fail-safe for non-pep508 formats
|
|
63
|
-
return False
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
class AnacondaPackages:
|
|
67
|
-
def __init__(self, packages: Dict[str, AvailablePackage]):
|
|
68
|
-
"""
|
|
69
|
-
[packages] should be a dictionary mapping package name to AnacondaPackageData object.
|
|
70
|
-
All package names should be provided in wheel escape format:
|
|
71
|
-
https://peps.python.org/pep-0491/#escaping-and-unicode
|
|
72
|
-
"""
|
|
73
|
-
self._packages = packages
|
|
74
|
-
|
|
75
|
-
@classmethod
|
|
76
|
-
def empty(cls):
|
|
77
|
-
return cls({})
|
|
78
|
-
|
|
79
|
-
def is_package_available(
|
|
80
|
-
self, package: Requirement, skip_version_check: bool = False
|
|
81
|
-
) -> bool:
|
|
82
|
-
"""
|
|
83
|
-
Checks of a requirement is available in the Snowflake Anaconda Channel.
|
|
84
|
-
|
|
85
|
-
As Snowflake currently doesn't support extra syntax (ex. `jinja2[diagrams]`), if such
|
|
86
|
-
extra is present in the dependency, we mark it as unavailable.
|
|
87
|
-
"""
|
|
88
|
-
if not package.name or package.extras:
|
|
89
|
-
return False
|
|
90
|
-
if package.name not in self._packages:
|
|
91
|
-
return False
|
|
92
|
-
if skip_version_check or not package.specs:
|
|
93
|
-
return True
|
|
94
|
-
return self._packages[package.name].is_required_version_available(package)
|
|
95
|
-
|
|
96
|
-
def package_latest_version(self, package: Requirement) -> str | None:
|
|
97
|
-
"""Returns the latest version of the package or None if the latest version can't be determined."""
|
|
98
|
-
if package.name not in self._packages:
|
|
99
|
-
return None
|
|
100
|
-
try:
|
|
101
|
-
return str(max(self._packages[package.name].iter_versions()))
|
|
102
|
-
except InvalidVersion:
|
|
103
|
-
# fail-safe for non-pep8 versions
|
|
104
|
-
return None
|
|
105
|
-
|
|
106
|
-
def package_versions(self, package: Requirement) -> List[str]:
|
|
107
|
-
"""Returns list of available versions of the package."""
|
|
108
|
-
if package.name not in self._packages:
|
|
109
|
-
return []
|
|
110
|
-
package_data = self._packages[package.name]
|
|
111
|
-
try:
|
|
112
|
-
return list(
|
|
113
|
-
str(x) for x in sorted(package_data.iter_versions(), reverse=True)
|
|
114
|
-
)
|
|
115
|
-
except InvalidVersion:
|
|
116
|
-
return list(sorted(package_data.versions, reverse=True))
|
|
117
|
-
|
|
118
|
-
def filter_available_packages(
|
|
119
|
-
self, packages: List[Requirement], skip_version_check: bool = False
|
|
120
|
-
) -> FilterRequirementsResult:
|
|
121
|
-
"""
|
|
122
|
-
Checks if a list of packages are available in the Snowflake Anaconda channel.
|
|
123
|
-
Returns an object with two attributes: 'snowflake' and 'other'.
|
|
124
|
-
Each key contains a list of Requirement object.
|
|
125
|
-
|
|
126
|
-
Parameters:
|
|
127
|
-
packages (List[Requirement]) - list of requirements to be checked
|
|
128
|
-
skip_version_check (bool) - skip comparing versions of packages
|
|
129
|
-
|
|
130
|
-
Returns:
|
|
131
|
-
result (FilterRequirementsResult) - object containing two arguments:
|
|
132
|
-
- in_snowflake - packages available in conda
|
|
133
|
-
- unavailable - packages not available in conda
|
|
134
|
-
"""
|
|
135
|
-
result = FilterRequirementsResult([], [])
|
|
136
|
-
for package in packages:
|
|
137
|
-
if self.is_package_available(
|
|
138
|
-
package, skip_version_check=skip_version_check
|
|
139
|
-
):
|
|
140
|
-
result.in_snowflake.append(package)
|
|
141
|
-
else:
|
|
142
|
-
log.info(
|
|
143
|
-
"'%s' not found in Snowflake Anaconda channel (or ignored)...",
|
|
144
|
-
package.name,
|
|
145
|
-
)
|
|
146
|
-
result.unavailable.append(package)
|
|
147
|
-
return result
|
|
148
|
-
|
|
149
|
-
def write_requirements_file_in_snowflake_format(
|
|
150
|
-
self,
|
|
151
|
-
file_path: SecurePath,
|
|
152
|
-
requirements: List[Requirement],
|
|
153
|
-
):
|
|
154
|
-
"""Saves requirements to a file in format accepted by Snowflake SQL commands."""
|
|
155
|
-
log.info("Writing requirements into file %s", file_path.path)
|
|
156
|
-
formatted_requirements = []
|
|
157
|
-
for requirement in requirements:
|
|
158
|
-
if requirement.name and requirement.name in self._packages:
|
|
159
|
-
snowflake_name = self._packages[requirement.name].snowflake_name
|
|
160
|
-
formatted_requirements.append(
|
|
161
|
-
snowflake_name + requirement.formatted_specs
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
if formatted_requirements:
|
|
165
|
-
file_path.write_text("\n".join(formatted_requirements))
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
class AnacondaPackagesManager(SqlExecutionMixin):
|
|
169
|
-
_snowflake_channel_url: str = (
|
|
170
|
-
"https://repo.anaconda.com/pkgs/snowflake/channeldata.json"
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
# TODO in v3.0: Keep only SQL query, remove fallback to JSON with channel's metadata
|
|
174
|
-
def find_packages_available_in_snowflake_anaconda(self) -> AnacondaPackages:
|
|
175
|
-
"""
|
|
176
|
-
Finds python packages available in Snowflake to use in functions and stored procedures.
|
|
177
|
-
It tries to get the list of packages using SQL query
|
|
178
|
-
but if the try fails then the fallback is to parse JSON containing info about Snowflake's Anaconda channel.
|
|
179
|
-
"""
|
|
180
|
-
try:
|
|
181
|
-
packages = self._query_snowflake_for_available_packages()
|
|
182
|
-
except Exception as ex:
|
|
183
|
-
log.warning(
|
|
184
|
-
"Cannot fetch available packages information from Snowflake. "
|
|
185
|
-
"Please check your connection configuration. "
|
|
186
|
-
"Fallback to Anaconda channel metadata."
|
|
187
|
-
)
|
|
188
|
-
log.debug("Available packages query failure: %s", ex.__str__(), exc_info=ex)
|
|
189
|
-
packages = self._get_available_packages_from_anaconda_channel_info()
|
|
190
|
-
return AnacondaPackages(packages)
|
|
191
|
-
|
|
192
|
-
def _query_snowflake_for_available_packages(self) -> dict[str, AvailablePackage]:
|
|
193
|
-
cursor = self._execute_query(
|
|
194
|
-
"select package_name, version from information_schema.packages where language = 'python'",
|
|
195
|
-
cursor_class=DictCursor,
|
|
196
|
-
)
|
|
197
|
-
if cursor.rowcount is None or cursor.rowcount == 0:
|
|
198
|
-
raise SnowflakeSQLExecutionError()
|
|
199
|
-
packages: dict[str, AvailablePackage] = {}
|
|
200
|
-
for row in cursor:
|
|
201
|
-
if not (package_name := row["PACKAGE_NAME"]):
|
|
202
|
-
continue
|
|
203
|
-
if not (version := row["VERSION"]):
|
|
204
|
-
continue
|
|
205
|
-
standardized_name = Requirement.standardize_name(package_name)
|
|
206
|
-
if standardized_name in packages:
|
|
207
|
-
packages[standardized_name].versions.add(version)
|
|
208
|
-
else:
|
|
209
|
-
packages[standardized_name] = AvailablePackage(
|
|
210
|
-
snowflake_name=package_name, versions={version}
|
|
211
|
-
)
|
|
212
|
-
return packages
|
|
213
|
-
|
|
214
|
-
def _get_available_packages_from_anaconda_channel_info(
|
|
215
|
-
self,
|
|
216
|
-
) -> dict[str, AvailablePackage]:
|
|
217
|
-
try:
|
|
218
|
-
response = requests.get(self._snowflake_channel_url)
|
|
219
|
-
response.raise_for_status()
|
|
220
|
-
packages = {}
|
|
221
|
-
for key, package in response.json()["packages"].items():
|
|
222
|
-
if not (version := package.get("version")):
|
|
223
|
-
continue
|
|
224
|
-
package_name = package.get("name", key)
|
|
225
|
-
standardized_name = Requirement.standardize_name(package_name)
|
|
226
|
-
packages[standardized_name] = AvailablePackage(
|
|
227
|
-
snowflake_name=package_name, versions={version}
|
|
228
|
-
)
|
|
229
|
-
return packages
|
|
230
|
-
except HTTPError as err:
|
|
231
|
-
raise ClickException(
|
|
232
|
-
f"Accessing Snowflake Anaconda channel failed. Reason {err}"
|
|
233
|
-
)
|
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from __future__ import annotations
|
|
16
|
-
|
|
17
|
-
import logging
|
|
18
|
-
from pathlib import Path
|
|
19
|
-
from textwrap import dedent
|
|
20
|
-
from typing import Optional
|
|
21
|
-
|
|
22
|
-
import typer
|
|
23
|
-
from click import ClickException
|
|
24
|
-
from snowflake.cli.api.commands.flags import (
|
|
25
|
-
deprecated_flag_callback,
|
|
26
|
-
)
|
|
27
|
-
from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
|
|
28
|
-
from snowflake.cli.api.output.types import CommandResult, MessageResult
|
|
29
|
-
from snowflake.cli.api.secure_path import SecurePath
|
|
30
|
-
from snowflake.cli.plugins.snowpark.models import (
|
|
31
|
-
Requirement,
|
|
32
|
-
YesNoAsk,
|
|
33
|
-
)
|
|
34
|
-
from snowflake.cli.plugins.snowpark.package.anaconda_packages import (
|
|
35
|
-
AnacondaPackages,
|
|
36
|
-
AnacondaPackagesManager,
|
|
37
|
-
)
|
|
38
|
-
from snowflake.cli.plugins.snowpark.package.manager import upload
|
|
39
|
-
from snowflake.cli.plugins.snowpark.package_utils import (
|
|
40
|
-
detect_and_log_shared_libraries,
|
|
41
|
-
download_unavailable_packages,
|
|
42
|
-
get_package_name_from_pip_wheel,
|
|
43
|
-
)
|
|
44
|
-
from snowflake.cli.plugins.snowpark.snowpark_shared import (
|
|
45
|
-
AllowSharedLibrariesOption,
|
|
46
|
-
IgnoreAnacondaOption,
|
|
47
|
-
IndexUrlOption,
|
|
48
|
-
SkipVersionCheckOption,
|
|
49
|
-
deprecated_allow_native_libraries_option,
|
|
50
|
-
resolve_allow_shared_libraries_yes_no_ask,
|
|
51
|
-
)
|
|
52
|
-
from snowflake.cli.plugins.snowpark.zipper import zip_dir
|
|
53
|
-
|
|
54
|
-
app = SnowTyperFactory(
|
|
55
|
-
name="package",
|
|
56
|
-
help="Manages custom Python packages for Snowpark",
|
|
57
|
-
)
|
|
58
|
-
log = logging.getLogger(__name__)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
lookup_install_option = typer.Option(
|
|
62
|
-
False,
|
|
63
|
-
"--pypi-download",
|
|
64
|
-
hidden=True,
|
|
65
|
-
callback=deprecated_flag_callback(
|
|
66
|
-
"Using --pypi-download is deprecated. Lookup command no longer checks for package in PyPi."
|
|
67
|
-
),
|
|
68
|
-
help="Installs packages that are not available on the Snowflake Anaconda channel.",
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
lookup_deprecated_install_option = typer.Option(
|
|
72
|
-
False,
|
|
73
|
-
"--yes",
|
|
74
|
-
"-y",
|
|
75
|
-
hidden=True,
|
|
76
|
-
callback=deprecated_flag_callback(
|
|
77
|
-
"Using --yes is deprecated. Lookup command no longer checks for package in PyPi."
|
|
78
|
-
),
|
|
79
|
-
help="Installs packages that are not available on the Snowflake Anaconda channel.",
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
@app.command("lookup", requires_connection=True)
|
|
84
|
-
def package_lookup(
|
|
85
|
-
package_name: str = typer.Argument(
|
|
86
|
-
..., help="Name of the package.", show_default=False
|
|
87
|
-
),
|
|
88
|
-
# todo: remove with 3.0
|
|
89
|
-
_: bool = lookup_install_option,
|
|
90
|
-
__: bool = lookup_deprecated_install_option,
|
|
91
|
-
**options,
|
|
92
|
-
) -> CommandResult:
|
|
93
|
-
"""
|
|
94
|
-
Checks if a package is available on the Snowflake Anaconda channel.
|
|
95
|
-
"""
|
|
96
|
-
anaconda_packages_manager = AnacondaPackagesManager()
|
|
97
|
-
anaconda_packages = (
|
|
98
|
-
anaconda_packages_manager.find_packages_available_in_snowflake_anaconda()
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
package = Requirement.parse(package_name)
|
|
102
|
-
if anaconda_packages.is_package_available(package=package):
|
|
103
|
-
msg = f"Package `{package_name}` is available in Anaconda"
|
|
104
|
-
if version := anaconda_packages.package_latest_version(package=package):
|
|
105
|
-
msg += f". Latest available version: {version}."
|
|
106
|
-
elif versions := anaconda_packages.package_versions(package=package):
|
|
107
|
-
msg += f" in versions: {', '.join(versions)}."
|
|
108
|
-
return MessageResult(msg)
|
|
109
|
-
|
|
110
|
-
return MessageResult(
|
|
111
|
-
dedent(
|
|
112
|
-
f"""
|
|
113
|
-
Package `{package_name}` is not available in Anaconda. To prepare Snowpark compatible package run:
|
|
114
|
-
snow snowpark package create {package_name}
|
|
115
|
-
"""
|
|
116
|
-
)
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
@app.command("upload", requires_connection=True)
|
|
121
|
-
def package_upload(
|
|
122
|
-
file: Path = typer.Option(
|
|
123
|
-
...,
|
|
124
|
-
"--file",
|
|
125
|
-
"-f",
|
|
126
|
-
help="Path to the file to upload.",
|
|
127
|
-
exists=False,
|
|
128
|
-
),
|
|
129
|
-
stage: str = typer.Option(
|
|
130
|
-
...,
|
|
131
|
-
"--stage",
|
|
132
|
-
"-s",
|
|
133
|
-
help="Name of the stage in which to upload the file, not including the @ symbol.",
|
|
134
|
-
),
|
|
135
|
-
overwrite: bool = typer.Option(
|
|
136
|
-
False,
|
|
137
|
-
"--overwrite",
|
|
138
|
-
"-o",
|
|
139
|
-
help="Overwrites the file if it already exists.",
|
|
140
|
-
),
|
|
141
|
-
**options,
|
|
142
|
-
) -> CommandResult:
|
|
143
|
-
"""
|
|
144
|
-
Uploads a Python package zip file to a Snowflake stage so it can be referenced in the imports of a procedure or function.
|
|
145
|
-
"""
|
|
146
|
-
return MessageResult(upload(file=file, stage=stage, overwrite=overwrite))
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
deprecated_pypi_download_option = typer.Option(
|
|
150
|
-
False,
|
|
151
|
-
"--pypi-download",
|
|
152
|
-
hidden=True,
|
|
153
|
-
callback=deprecated_flag_callback(
|
|
154
|
-
"Using --pypi-download is deprecated. Create command always checks for package in PyPi."
|
|
155
|
-
),
|
|
156
|
-
help="Installs packages that are not available on the Snowflake Anaconda channel.",
|
|
157
|
-
)
|
|
158
|
-
|
|
159
|
-
deprecated_install_option = typer.Option(
|
|
160
|
-
False,
|
|
161
|
-
"--yes",
|
|
162
|
-
"-y",
|
|
163
|
-
hidden=True,
|
|
164
|
-
help="Installs packages that are not available on the Snowflake Anaconda channel.",
|
|
165
|
-
callback=deprecated_flag_callback(
|
|
166
|
-
"Using --yes is deprecated. Create command always checks for package in PyPi."
|
|
167
|
-
),
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
@app.command("create", requires_connection=True)
|
|
172
|
-
def package_create(
|
|
173
|
-
name: str = typer.Argument(
|
|
174
|
-
...,
|
|
175
|
-
help="Name of the package to create.",
|
|
176
|
-
),
|
|
177
|
-
ignore_anaconda: bool = IgnoreAnacondaOption,
|
|
178
|
-
index_url: Optional[str] = IndexUrlOption,
|
|
179
|
-
skip_version_check: bool = SkipVersionCheckOption,
|
|
180
|
-
allow_shared_libraries: bool = AllowSharedLibrariesOption,
|
|
181
|
-
deprecated_allow_native_libraries: YesNoAsk = deprecated_allow_native_libraries_option(
|
|
182
|
-
"--allow-native-libraries"
|
|
183
|
-
),
|
|
184
|
-
_deprecated_install_option: bool = deprecated_install_option,
|
|
185
|
-
_deprecated_install_packages: bool = deprecated_pypi_download_option,
|
|
186
|
-
**options,
|
|
187
|
-
) -> CommandResult:
|
|
188
|
-
"""
|
|
189
|
-
Creates a Python package as a zip file that can be uploaded to a stage and imported for a Snowpark Python app.
|
|
190
|
-
"""
|
|
191
|
-
with SecurePath.temporary_directory() as packages_dir:
|
|
192
|
-
package = Requirement.parse(name)
|
|
193
|
-
anaconda_packages_manager = AnacondaPackagesManager()
|
|
194
|
-
download_result = download_unavailable_packages(
|
|
195
|
-
requirements=[package],
|
|
196
|
-
target_dir=packages_dir,
|
|
197
|
-
anaconda_packages=(
|
|
198
|
-
AnacondaPackages.empty()
|
|
199
|
-
if ignore_anaconda
|
|
200
|
-
else anaconda_packages_manager.find_packages_available_in_snowflake_anaconda()
|
|
201
|
-
),
|
|
202
|
-
skip_version_check=skip_version_check,
|
|
203
|
-
pip_index_url=index_url,
|
|
204
|
-
)
|
|
205
|
-
if not download_result.succeeded:
|
|
206
|
-
raise ClickException(download_result.error_message)
|
|
207
|
-
|
|
208
|
-
# check if package was detected as available
|
|
209
|
-
package_available_in_conda = any(
|
|
210
|
-
p.line == package.line for p in download_result.anaconda_packages
|
|
211
|
-
)
|
|
212
|
-
if package_available_in_conda:
|
|
213
|
-
return MessageResult(
|
|
214
|
-
f"Package {name} is already available in Snowflake Anaconda Channel."
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
# The package is not in anaconda, so we have to pack it
|
|
218
|
-
log.info("Checking to see if packages have shared (.so/.dll) libraries...")
|
|
219
|
-
if detect_and_log_shared_libraries(download_result.downloaded_packages_details):
|
|
220
|
-
# TODO: yes/no/ask logic should be removed in 3.0
|
|
221
|
-
if not (
|
|
222
|
-
allow_shared_libraries
|
|
223
|
-
or resolve_allow_shared_libraries_yes_no_ask(
|
|
224
|
-
deprecated_allow_native_libraries
|
|
225
|
-
)
|
|
226
|
-
):
|
|
227
|
-
raise ClickException(
|
|
228
|
-
"Some packages contain shared (.so/.dll) libraries. "
|
|
229
|
-
"Try again with --allow-shared-libraries."
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
-
# The package is not in anaconda, so we have to pack it
|
|
233
|
-
# the package was downloaded once, pip wheel should use cache
|
|
234
|
-
zip_file = f"{get_package_name_from_pip_wheel(name, index_url=index_url)}.zip"
|
|
235
|
-
zip_dir(dest_zip=Path(zip_file), source=packages_dir.path)
|
|
236
|
-
message = dedent(
|
|
237
|
-
f"""
|
|
238
|
-
Package {zip_file} created. You can now upload it to a stage using
|
|
239
|
-
snow snowpark package upload -f {zip_file} -s <stage-name>`
|
|
240
|
-
and reference it in your procedure or function.
|
|
241
|
-
Remember to add it to imports in the procedure or function definition.
|
|
242
|
-
"""
|
|
243
|
-
)
|
|
244
|
-
if download_result.anaconda_packages:
|
|
245
|
-
message += dedent(
|
|
246
|
-
f"""
|
|
247
|
-
The package {name} is successfully created, but depends on the following
|
|
248
|
-
Anaconda libraries. They need to be included in project requirements,
|
|
249
|
-
as their are not included in .zip.
|
|
250
|
-
"""
|
|
251
|
-
)
|
|
252
|
-
message += "\n".join(
|
|
253
|
-
(req.line for req in download_result.anaconda_packages)
|
|
254
|
-
)
|
|
255
|
-
|
|
256
|
-
return MessageResult(message)
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from __future__ import annotations
|
|
16
|
-
|
|
17
|
-
import logging
|
|
18
|
-
from pathlib import Path
|
|
19
|
-
|
|
20
|
-
from snowflake.cli.api.secure_path import SecurePath
|
|
21
|
-
from snowflake.cli.plugins.snowpark.package.utils import prepare_app_zip
|
|
22
|
-
from snowflake.cli.plugins.stage.manager import StageManager
|
|
23
|
-
|
|
24
|
-
log = logging.getLogger(__name__)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def upload(file: Path, stage: str, overwrite: bool):
|
|
28
|
-
log.info("Uploading %s to Snowflake @%s/%s...", file, stage, file)
|
|
29
|
-
with SecurePath.temporary_directory() as temp_dir:
|
|
30
|
-
temp_app_zip_path = prepare_app_zip(SecurePath(file), temp_dir)
|
|
31
|
-
sm = StageManager()
|
|
32
|
-
|
|
33
|
-
sm.create(sm.get_stage_from_path(stage))
|
|
34
|
-
put_response = sm.put(
|
|
35
|
-
temp_app_zip_path.path, stage, overwrite=overwrite
|
|
36
|
-
).fetchone()
|
|
37
|
-
|
|
38
|
-
message = f"Package {file} {put_response[6]} to Snowflake @{stage}/{file}."
|
|
39
|
-
|
|
40
|
-
if put_response[6] == "SKIPPED":
|
|
41
|
-
message = "Package already exists on stage. Consider using --overwrite to overwrite the file."
|
|
42
|
-
|
|
43
|
-
return message
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2024 Snowflake Inc.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from __future__ import annotations
|
|
16
|
-
|
|
17
|
-
from snowflake.cli.api.secure_path import SecurePath
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def prepare_app_zip(file_path: SecurePath, temp_dir: SecurePath) -> SecurePath:
|
|
21
|
-
# get filename from file path (e.g. app.zip from /path/to/app.zip)
|
|
22
|
-
# TODO: think if no file exceptions are handled correctly
|
|
23
|
-
file_name = file_path.path.name
|
|
24
|
-
temp_path = temp_dir / file_name
|
|
25
|
-
file_path.copy(temp_path.path)
|
|
26
|
-
return temp_path
|