snowflake-cli 3.3.0__py3-none-any.whl → 3.5.0__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/_app/__main__.py +2 -2
- snowflake/cli/_app/cli_app.py +220 -197
- snowflake/cli/_app/commands_registration/builtin_plugins.py +5 -1
- snowflake/cli/_app/commands_registration/command_plugins_loader.py +3 -1
- snowflake/cli/_app/commands_registration/commands_registration_with_callbacks.py +4 -30
- snowflake/cli/_app/printing.py +2 -2
- snowflake/cli/_plugins/connection/commands.py +2 -4
- snowflake/cli/_plugins/cortex/commands.py +2 -4
- snowflake/cli/_plugins/git/manager.py +1 -1
- snowflake/cli/_plugins/helpers/commands.py +3 -4
- snowflake/cli/_plugins/nativeapp/artifacts.py +6 -624
- snowflake/cli/_plugins/nativeapp/bundle_context.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +1 -1
- snowflake/cli/_plugins/nativeapp/codegen/compiler.py +1 -3
- snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +2 -2
- snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +2 -2
- snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +2 -2
- snowflake/cli/_plugins/nativeapp/commands.py +21 -19
- snowflake/cli/_plugins/nativeapp/entities/application.py +16 -19
- snowflake/cli/_plugins/nativeapp/entities/application_package.py +142 -55
- snowflake/cli/_plugins/nativeapp/release_channel/commands.py +37 -3
- snowflake/cli/_plugins/nativeapp/release_directive/commands.py +80 -2
- snowflake/cli/_plugins/nativeapp/sf_sql_facade.py +224 -44
- snowflake/cli/_plugins/nativeapp/v2_conversions/compat.py +2 -2
- snowflake/cli/_plugins/nativeapp/version/commands.py +1 -1
- snowflake/cli/_plugins/notebook/commands.py +54 -2
- snowflake/cli/_plugins/notebook/exceptions.py +1 -1
- snowflake/cli/_plugins/notebook/manager.py +3 -3
- snowflake/cli/_plugins/notebook/notebook_entity.py +120 -0
- snowflake/cli/_plugins/notebook/notebook_entity_model.py +42 -0
- snowflake/cli/_plugins/notebook/notebook_project_paths.py +15 -0
- snowflake/cli/_plugins/notebook/types.py +3 -0
- snowflake/cli/_plugins/plugin/commands.py +79 -0
- snowflake/cli/_plugins/plugin/manager.py +74 -0
- snowflake/cli/_plugins/plugin/plugin_spec.py +30 -0
- snowflake/cli/_plugins/project/__init__.py +0 -0
- snowflake/cli/_plugins/project/commands.py +157 -0
- snowflake/cli/_plugins/project/feature_flags.py +22 -0
- snowflake/cli/_plugins/project/manager.py +76 -0
- snowflake/cli/_plugins/project/plugin_spec.py +30 -0
- snowflake/cli/_plugins/project/project_entity_model.py +40 -0
- snowflake/cli/_plugins/snowpark/commands.py +49 -30
- snowflake/cli/_plugins/snowpark/common.py +47 -2
- snowflake/cli/_plugins/snowpark/snowpark_entity.py +38 -25
- snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +18 -30
- snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +156 -23
- snowflake/cli/_plugins/snowpark/zipper.py +33 -1
- snowflake/cli/_plugins/spcs/compute_pool/commands.py +53 -5
- snowflake/cli/_plugins/spcs/compute_pool/compute_pool_entity.py +8 -0
- snowflake/cli/_plugins/spcs/compute_pool/compute_pool_entity_model.py +37 -0
- snowflake/cli/_plugins/spcs/compute_pool/manager.py +45 -0
- snowflake/cli/_plugins/spcs/image_repository/commands.py +29 -0
- snowflake/cli/_plugins/spcs/image_repository/image_repository_entity.py +8 -0
- snowflake/cli/_plugins/spcs/image_repository/image_repository_entity_model.py +8 -0
- snowflake/cli/_plugins/spcs/image_repository/manager.py +1 -1
- snowflake/cli/_plugins/spcs/services/commands.py +51 -1
- snowflake/cli/_plugins/spcs/services/manager.py +114 -0
- snowflake/cli/_plugins/spcs/services/service_entity.py +6 -0
- snowflake/cli/_plugins/spcs/services/service_entity_model.py +45 -0
- snowflake/cli/_plugins/spcs/services/service_project_paths.py +15 -0
- snowflake/cli/_plugins/stage/commands.py +2 -1
- snowflake/cli/_plugins/stage/diff.py +60 -39
- snowflake/cli/_plugins/stage/manager.py +26 -13
- snowflake/cli/_plugins/stage/utils.py +1 -1
- snowflake/cli/_plugins/streamlit/commands.py +18 -24
- snowflake/cli/_plugins/streamlit/manager.py +37 -27
- snowflake/cli/_plugins/streamlit/streamlit_entity.py +20 -41
- snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +14 -24
- snowflake/cli/_plugins/streamlit/streamlit_project_paths.py +30 -0
- snowflake/cli/_plugins/workspace/commands.py +3 -3
- snowflake/cli/_plugins/workspace/manager.py +1 -1
- snowflake/cli/api/artifacts/bundle_map.py +500 -0
- snowflake/cli/api/artifacts/common.py +78 -0
- snowflake/cli/api/artifacts/upload.py +51 -0
- snowflake/cli/api/artifacts/utils.py +82 -0
- snowflake/cli/api/cli_global_context.py +14 -1
- snowflake/cli/api/commands/flags.py +34 -13
- snowflake/cli/api/commands/snow_typer.py +12 -0
- snowflake/cli/api/commands/utils.py +30 -2
- snowflake/cli/api/config.py +15 -10
- snowflake/cli/api/constants.py +1 -0
- snowflake/cli/api/entities/common.py +14 -32
- snowflake/cli/api/entities/resolver.py +160 -0
- snowflake/cli/api/entities/utils.py +56 -15
- snowflake/cli/api/errno.py +3 -0
- snowflake/cli/api/exceptions.py +8 -1
- snowflake/cli/api/feature_flags.py +1 -1
- snowflake/cli/api/plugins/plugin_config.py +43 -4
- snowflake/cli/api/project/definition_conversion.py +3 -2
- snowflake/cli/api/project/definition_helper.py +31 -0
- snowflake/cli/api/project/project_paths.py +28 -0
- snowflake/cli/api/project/schemas/entities/common.py +130 -1
- snowflake/cli/api/project/schemas/entities/entities.py +30 -0
- snowflake/cli/api/project/schemas/project_definition.py +27 -0
- snowflake/cli/api/project/schemas/updatable_model.py +2 -2
- snowflake/cli/api/project/schemas/v1/native_app/native_app.py +5 -7
- snowflake/cli/api/secure_path.py +6 -0
- snowflake/cli/api/sql_execution.py +5 -1
- snowflake/cli/api/stage_path.py +7 -2
- snowflake/cli/api/utils/graph.py +3 -0
- snowflake/cli/api/utils/path_utils.py +24 -0
- {snowflake_cli-3.3.0.dist-info → snowflake_cli-3.5.0.dist-info}/METADATA +12 -13
- {snowflake_cli-3.3.0.dist-info → snowflake_cli-3.5.0.dist-info}/RECORD +109 -85
- snowflake/cli/_app/api_impl/plugin/plugin_config_provider_impl.py +0 -66
- snowflake/cli/api/__init__.py +0 -48
- snowflake/cli/api/project/schemas/v1/native_app/path_mapping.py +0 -65
- /snowflake/cli/{_app/api_impl → _plugins/plugin}/__init__.py +0 -0
- /snowflake/cli/{_app/api_impl/plugin → api/artifacts}/__init__.py +0 -0
- {snowflake_cli-3.3.0.dist-info → snowflake_cli-3.5.0.dist-info}/WHEEL +0 -0
- {snowflake_cli-3.3.0.dist-info → snowflake_cli-3.5.0.dist-info}/entry_points.txt +0 -0
- {snowflake_cli-3.3.0.dist-info → snowflake_cli-3.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -39,7 +39,9 @@ from snowflake.cli._plugins.snowpark.common import (
|
|
|
39
39
|
SnowparkEntities,
|
|
40
40
|
SnowparkObject,
|
|
41
41
|
SnowparkObjectManager,
|
|
42
|
-
|
|
42
|
+
StageToArtifactMapping,
|
|
43
|
+
map_path_mapping_to_artifact,
|
|
44
|
+
zip_and_copy_artifacts_to_deploy,
|
|
43
45
|
)
|
|
44
46
|
from snowflake.cli._plugins.snowpark.package.anaconda_packages import (
|
|
45
47
|
AnacondaPackages,
|
|
@@ -68,6 +70,7 @@ from snowflake.cli.api.commands.decorators import (
|
|
|
68
70
|
with_project_definition,
|
|
69
71
|
)
|
|
70
72
|
from snowflake.cli.api.commands.flags import (
|
|
73
|
+
ForceReplaceOption,
|
|
71
74
|
ReplaceOption,
|
|
72
75
|
execution_identifier_argument,
|
|
73
76
|
identifier_argument,
|
|
@@ -81,6 +84,7 @@ from snowflake.cli.api.constants import (
|
|
|
81
84
|
from snowflake.cli.api.exceptions import (
|
|
82
85
|
SecretsWithoutExternalAccessIntegrationError,
|
|
83
86
|
)
|
|
87
|
+
from snowflake.cli.api.feature_flags import FeatureFlag
|
|
84
88
|
from snowflake.cli.api.identifiers import FQN
|
|
85
89
|
from snowflake.cli.api.output.types import (
|
|
86
90
|
CollectionResult,
|
|
@@ -125,8 +129,10 @@ LikeOption = like_option(
|
|
|
125
129
|
@with_project_definition()
|
|
126
130
|
def deploy(
|
|
127
131
|
replace: bool = ReplaceOption(
|
|
128
|
-
help="Replaces procedure or function
|
|
132
|
+
help="Replaces procedure or function if there were changes in the definition. It only uploads new and "
|
|
133
|
+
"overwrites existing files, but does not remove any files already on the stage."
|
|
129
134
|
),
|
|
135
|
+
force_replace: bool = ForceReplaceOption(),
|
|
130
136
|
**options,
|
|
131
137
|
) -> CommandResult:
|
|
132
138
|
"""
|
|
@@ -156,7 +162,11 @@ def deploy(
|
|
|
156
162
|
with cli_console.phase("Checking remote state"):
|
|
157
163
|
om = ObjectManager()
|
|
158
164
|
_check_if_all_defined_integrations_exists(om, snowpark_entities)
|
|
159
|
-
existing_objects =
|
|
165
|
+
existing_objects = (
|
|
166
|
+
{}
|
|
167
|
+
if force_replace
|
|
168
|
+
else check_for_existing_objects(om, replace, snowpark_entities)
|
|
169
|
+
)
|
|
160
170
|
|
|
161
171
|
with cli_console.phase("Preparing required stages and artifacts"):
|
|
162
172
|
entities_to_imports_map, stages_to_artifact_map = build_artifacts_mappings(
|
|
@@ -189,11 +199,11 @@ def validate_all_artifacts_exists(
|
|
|
189
199
|
project_paths: SnowparkProjectPaths, snowpark_entities: SnowparkEntities
|
|
190
200
|
):
|
|
191
201
|
for key, entity in snowpark_entities.items():
|
|
192
|
-
for
|
|
193
|
-
path = project_paths.
|
|
202
|
+
for artifact in entity.artifacts:
|
|
203
|
+
path = project_paths.get_artifact_dto(artifact).post_build_path
|
|
194
204
|
if not path.exists():
|
|
195
205
|
raise UsageError(
|
|
196
|
-
f"
|
|
206
|
+
f"Artifact {path} required for {entity.type} {key} does not exist."
|
|
197
207
|
)
|
|
198
208
|
|
|
199
209
|
|
|
@@ -213,38 +223,39 @@ def check_for_existing_objects(
|
|
|
213
223
|
|
|
214
224
|
def build_artifacts_mappings(
|
|
215
225
|
project_paths: SnowparkProjectPaths, snowpark_entities: SnowparkEntities
|
|
216
|
-
) -> Tuple[EntityToImportPathsMapping,
|
|
217
|
-
stages_to_artifact_map:
|
|
226
|
+
) -> Tuple[EntityToImportPathsMapping, StageToArtifactMapping]:
|
|
227
|
+
stages_to_artifact_map: StageToArtifactMapping = defaultdict(set)
|
|
218
228
|
entities_to_imports_map: EntityToImportPathsMapping = defaultdict(set)
|
|
219
|
-
for
|
|
229
|
+
for name, entity in snowpark_entities.items():
|
|
220
230
|
stage = entity.stage
|
|
221
231
|
required_artifacts = set()
|
|
222
|
-
for
|
|
223
|
-
|
|
224
|
-
required_artifacts.add(
|
|
225
|
-
entities_to_imports_map[
|
|
232
|
+
for artifact in entity.artifacts:
|
|
233
|
+
artifact_dto = project_paths.get_artifact_dto(artifact)
|
|
234
|
+
required_artifacts.add(artifact_dto)
|
|
235
|
+
entities_to_imports_map[name].add(artifact_dto.import_path(stage))
|
|
226
236
|
stages_to_artifact_map[stage].update(required_artifacts)
|
|
227
237
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
stages_to_artifact_map[stage].add(
|
|
231
|
-
entities_to_imports_map[
|
|
238
|
+
deps_artifact = project_paths.get_dependencies_artifact()
|
|
239
|
+
if deps_artifact.post_build_path.exists():
|
|
240
|
+
stages_to_artifact_map[stage].add(deps_artifact)
|
|
241
|
+
entities_to_imports_map[name].add(deps_artifact.import_path(stage))
|
|
232
242
|
return entities_to_imports_map, stages_to_artifact_map
|
|
233
243
|
|
|
234
244
|
|
|
235
|
-
def create_stages_and_upload_artifacts(stages_to_artifact_map:
|
|
245
|
+
def create_stages_and_upload_artifacts(stages_to_artifact_map: StageToArtifactMapping):
|
|
236
246
|
stage_manager = StageManager()
|
|
237
247
|
for stage, artifacts in stages_to_artifact_map.items():
|
|
238
248
|
cli_console.step(f"Creating (if not exists) stage: {stage}")
|
|
239
249
|
stage = FQN.from_stage(stage).using_context()
|
|
240
250
|
stage_manager.create(fqn=stage, comment="deployments managed by Snowflake CLI")
|
|
241
|
-
for
|
|
251
|
+
for artifact in artifacts:
|
|
252
|
+
post_build_path = artifact.post_build_path
|
|
242
253
|
cli_console.step(
|
|
243
|
-
f"Uploading {
|
|
254
|
+
f"Uploading {post_build_path.name} to {artifact.upload_path(stage)}"
|
|
244
255
|
)
|
|
245
256
|
stage_manager.put(
|
|
246
|
-
local_path=
|
|
247
|
-
stage_path=
|
|
257
|
+
local_path=post_build_path,
|
|
258
|
+
stage_path=artifact.upload_path(stage),
|
|
248
259
|
overwrite=True,
|
|
249
260
|
)
|
|
250
261
|
|
|
@@ -324,6 +335,9 @@ def build(
|
|
|
324
335
|
|
|
325
336
|
anaconda_packages_manager = AnacondaPackagesManager()
|
|
326
337
|
|
|
338
|
+
# Clean up bundle root
|
|
339
|
+
project_paths.remove_up_bundle_root()
|
|
340
|
+
|
|
327
341
|
# Resolve dependencies
|
|
328
342
|
if project_paths.requirements.exists():
|
|
329
343
|
with (
|
|
@@ -362,22 +376,27 @@ def build(
|
|
|
362
376
|
)
|
|
363
377
|
|
|
364
378
|
if any(temp_deps_dir.path.iterdir()):
|
|
365
|
-
|
|
379
|
+
dep_artifact = project_paths.get_dependencies_artifact()
|
|
380
|
+
cli_console.step(f"Creating {dep_artifact.path.name}")
|
|
366
381
|
zip_dir(
|
|
367
382
|
source=temp_deps_dir.path,
|
|
368
|
-
dest_zip=
|
|
383
|
+
dest_zip=dep_artifact.post_build_path,
|
|
369
384
|
)
|
|
370
385
|
else:
|
|
371
386
|
cli_console.step(f"No external dependencies.")
|
|
372
387
|
|
|
373
388
|
artifacts = set()
|
|
374
|
-
for entity in get_snowpark_entities(pd).values():
|
|
375
|
-
artifacts.update(entity.artifacts)
|
|
376
|
-
|
|
377
389
|
with cli_console.phase("Preparing artifacts for source code"):
|
|
378
|
-
for
|
|
379
|
-
|
|
380
|
-
|
|
390
|
+
for entity in get_snowpark_entities(pd).values():
|
|
391
|
+
artifacts.update(
|
|
392
|
+
map_path_mapping_to_artifact(project_paths, entity.artifacts)
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
if FeatureFlag.ENABLE_SNOWPARK_GLOB_SUPPORT.is_enabled():
|
|
396
|
+
zip_and_copy_artifacts_to_deploy(artifacts, project_paths.bundle_root)
|
|
397
|
+
else:
|
|
398
|
+
for artifact in artifacts:
|
|
399
|
+
artifact.build()
|
|
381
400
|
|
|
382
401
|
return MessageResult(f"Build done.")
|
|
383
402
|
|
|
@@ -17,6 +17,7 @@ from __future__ import annotations
|
|
|
17
17
|
import logging
|
|
18
18
|
import re
|
|
19
19
|
from enum import Enum
|
|
20
|
+
from pathlib import Path
|
|
20
21
|
from typing import Dict, List, Set
|
|
21
22
|
|
|
22
23
|
from click import UsageError
|
|
@@ -25,7 +26,13 @@ from snowflake.cli._plugins.snowpark.snowpark_entity_model import (
|
|
|
25
26
|
ProcedureEntityModel,
|
|
26
27
|
SnowparkEntityModel,
|
|
27
28
|
)
|
|
28
|
-
from snowflake.cli._plugins.snowpark.snowpark_project_paths import
|
|
29
|
+
from snowflake.cli._plugins.snowpark.snowpark_project_paths import (
|
|
30
|
+
Artifact,
|
|
31
|
+
SnowparkProjectPaths,
|
|
32
|
+
)
|
|
33
|
+
from snowflake.cli._plugins.snowpark.zipper import zip_dir_using_bundle_map
|
|
34
|
+
from snowflake.cli.api.artifacts.bundle_map import BundleMap
|
|
35
|
+
from snowflake.cli.api.artifacts.utils import symlink_or_copy
|
|
29
36
|
from snowflake.cli.api.console import cli_console
|
|
30
37
|
from snowflake.cli.api.constants import (
|
|
31
38
|
INIT_TEMPLATE_VARIABLE_CLOSING,
|
|
@@ -34,13 +41,14 @@ from snowflake.cli.api.constants import (
|
|
|
34
41
|
PROJECT_TEMPLATE_VARIABLE_OPENING,
|
|
35
42
|
ObjectType,
|
|
36
43
|
)
|
|
44
|
+
from snowflake.cli.api.project.schemas.entities.common import PathMapping
|
|
37
45
|
from snowflake.cli.api.sql_execution import SqlExecutionMixin
|
|
38
46
|
from snowflake.connector.cursor import SnowflakeCursor
|
|
39
47
|
|
|
40
48
|
log = logging.getLogger(__name__)
|
|
41
49
|
|
|
42
50
|
SnowparkEntities = Dict[str, SnowparkEntityModel]
|
|
43
|
-
|
|
51
|
+
StageToArtifactMapping = Dict[str, set[Artifact]]
|
|
44
52
|
EntityToImportPathsMapping = Dict[str, set[str]]
|
|
45
53
|
|
|
46
54
|
DEFAULT_RUNTIME = "3.10"
|
|
@@ -214,6 +222,43 @@ def _snowflake_dependencies_differ(
|
|
|
214
222
|
return _standardize(old_dependencies) != _standardize(new_dependencies)
|
|
215
223
|
|
|
216
224
|
|
|
225
|
+
def map_path_mapping_to_artifact(
|
|
226
|
+
project_paths: SnowparkProjectPaths, artifacts: List[PathMapping]
|
|
227
|
+
) -> List[Artifact]:
|
|
228
|
+
return [project_paths.get_artifact_dto(artifact) for artifact in artifacts]
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def zip_and_copy_artifacts_to_deploy(
|
|
232
|
+
artifacts: Set[Artifact] | List[Artifact], bundle_root: Path
|
|
233
|
+
) -> List[Path]:
|
|
234
|
+
copied_files = []
|
|
235
|
+
for artifact in artifacts:
|
|
236
|
+
bundle_map = BundleMap(
|
|
237
|
+
project_root=artifact.project_root,
|
|
238
|
+
deploy_root=bundle_root,
|
|
239
|
+
)
|
|
240
|
+
bundle_map.add(PathMapping(src=str(artifact.path), dest=artifact.dest))
|
|
241
|
+
|
|
242
|
+
if artifact.path.is_file():
|
|
243
|
+
for (absolute_src, absolute_dest) in bundle_map.all_mappings(
|
|
244
|
+
absolute=True, expand_directories=False
|
|
245
|
+
):
|
|
246
|
+
symlink_or_copy(
|
|
247
|
+
absolute_src,
|
|
248
|
+
absolute_dest,
|
|
249
|
+
deploy_root=bundle_map.deploy_root(),
|
|
250
|
+
)
|
|
251
|
+
copied_files.append(absolute_dest)
|
|
252
|
+
else:
|
|
253
|
+
post_build_path = artifact.post_build_path
|
|
254
|
+
zip_dir_using_bundle_map(
|
|
255
|
+
bundle_map=bundle_map,
|
|
256
|
+
dest_zip=post_build_path,
|
|
257
|
+
)
|
|
258
|
+
copied_files.append(post_build_path)
|
|
259
|
+
return copied_files
|
|
260
|
+
|
|
261
|
+
|
|
217
262
|
def same_type(sf_type: str, local_type: str) -> bool:
|
|
218
263
|
sf_type, local_type = sf_type.upper(), local_type.upper()
|
|
219
264
|
|
|
@@ -5,7 +5,11 @@ from typing import Generic, List, Optional, TypeVar
|
|
|
5
5
|
from click import ClickException
|
|
6
6
|
from snowflake.cli._plugins.nativeapp.feature_flags import FeatureFlag
|
|
7
7
|
from snowflake.cli._plugins.snowpark import package_utils
|
|
8
|
-
from snowflake.cli._plugins.snowpark.common import
|
|
8
|
+
from snowflake.cli._plugins.snowpark.common import (
|
|
9
|
+
DEFAULT_RUNTIME,
|
|
10
|
+
map_path_mapping_to_artifact,
|
|
11
|
+
zip_and_copy_artifacts_to_deploy,
|
|
12
|
+
)
|
|
9
13
|
from snowflake.cli._plugins.snowpark.package.anaconda_packages import (
|
|
10
14
|
AnacondaPackages,
|
|
11
15
|
AnacondaPackagesManager,
|
|
@@ -17,6 +21,7 @@ from snowflake.cli._plugins.snowpark.snowpark_entity_model import (
|
|
|
17
21
|
FunctionEntityModel,
|
|
18
22
|
ProcedureEntityModel,
|
|
19
23
|
)
|
|
24
|
+
from snowflake.cli._plugins.snowpark.snowpark_project_paths import SnowparkProjectPaths
|
|
20
25
|
from snowflake.cli._plugins.snowpark.zipper import zip_dir
|
|
21
26
|
from snowflake.cli._plugins.workspace.context import ActionContext
|
|
22
27
|
from snowflake.cli.api.entities.common import EntityBase
|
|
@@ -44,27 +49,31 @@ class SnowparkEntity(EntityBase[Generic[T]]):
|
|
|
44
49
|
def action_bundle(
|
|
45
50
|
self,
|
|
46
51
|
action_ctx: ActionContext,
|
|
47
|
-
output_dir: Path | None,
|
|
48
52
|
ignore_anaconda: bool,
|
|
49
53
|
skip_version_check: bool,
|
|
54
|
+
output_dir: Path | None = None,
|
|
50
55
|
index_url: str | None = None,
|
|
51
56
|
allow_shared_libraries: bool = False,
|
|
52
57
|
*args,
|
|
53
58
|
**kwargs,
|
|
54
59
|
) -> List[Path]:
|
|
55
60
|
return self.bundle(
|
|
56
|
-
output_dir,
|
|
57
61
|
ignore_anaconda,
|
|
58
62
|
skip_version_check,
|
|
63
|
+
output_dir,
|
|
59
64
|
index_url,
|
|
60
65
|
allow_shared_libraries,
|
|
61
66
|
)
|
|
62
67
|
|
|
63
68
|
def action_deploy(
|
|
64
|
-
self,
|
|
69
|
+
self,
|
|
70
|
+
action_ctx: ActionContext,
|
|
71
|
+
mode: CreateMode = CreateMode.create,
|
|
72
|
+
*args,
|
|
73
|
+
**kwargs,
|
|
65
74
|
):
|
|
66
75
|
# TODO: After introducing bundle map, we should introduce file copying part here
|
|
67
|
-
return self.
|
|
76
|
+
return self.deploy(mode, *args, **kwargs)
|
|
68
77
|
|
|
69
78
|
def action_drop(self, action_ctx: ActionContext, *args, **kwargs):
|
|
70
79
|
return self._execute_query(self.get_drop_sql())
|
|
@@ -83,9 +92,9 @@ class SnowparkEntity(EntityBase[Generic[T]]):
|
|
|
83
92
|
|
|
84
93
|
def bundle(
|
|
85
94
|
self,
|
|
86
|
-
output_dir: Path | None,
|
|
87
95
|
ignore_anaconda: bool,
|
|
88
96
|
skip_version_check: bool,
|
|
97
|
+
output_dir: Path | None = None,
|
|
89
98
|
index_url: str | None = None,
|
|
90
99
|
allow_shared_libraries: bool = False,
|
|
91
100
|
) -> List[Path]:
|
|
@@ -93,18 +102,20 @@ class SnowparkEntity(EntityBase[Generic[T]]):
|
|
|
93
102
|
Bundles the entity artifacts and dependencies into a directory.
|
|
94
103
|
Parameters:
|
|
95
104
|
output_dir: The directory to output the bundled artifacts to. Defaults to output dir in project root
|
|
96
|
-
ignore_anaconda: If True, ignores anaconda
|
|
105
|
+
ignore_anaconda: If True, ignores anaconda check and tries to download all packages using pip
|
|
97
106
|
skip_version_check: If True, skips version check when downloading packages
|
|
98
107
|
index_url: The index URL to use when downloading packages, if none set - default pip index is used (in most cases- Pypi)
|
|
99
108
|
allow_shared_libraries: If not set to True, using dependency with .so/.dll files will raise an exception
|
|
100
109
|
Returns:
|
|
101
110
|
"""
|
|
102
111
|
# 0 Create a directory for the entity
|
|
112
|
+
project_paths = SnowparkProjectPaths(
|
|
113
|
+
project_root=self.root.absolute(),
|
|
114
|
+
)
|
|
103
115
|
if not output_dir:
|
|
104
|
-
output_dir =
|
|
105
|
-
output_dir.
|
|
106
|
-
|
|
107
|
-
output_files = []
|
|
116
|
+
output_dir = project_paths.bundle_root
|
|
117
|
+
if not output_dir.exists(): # type: ignore[union-attr]
|
|
118
|
+
SecurePath(output_dir).mkdir(parents=True)
|
|
108
119
|
|
|
109
120
|
# 1 Check if requirements exits
|
|
110
121
|
if (self.root / "requirements.txt").exists():
|
|
@@ -118,21 +129,20 @@ class SnowparkEntity(EntityBase[Generic[T]]):
|
|
|
118
129
|
allow_shared_libraries=allow_shared_libraries,
|
|
119
130
|
)
|
|
120
131
|
|
|
121
|
-
#
|
|
122
|
-
artifacts = self.model.artifacts
|
|
123
|
-
|
|
124
|
-
for artifact in artifacts:
|
|
125
|
-
output_file = output_dir / artifact.dest / artifact.src.name
|
|
126
|
-
|
|
127
|
-
if artifact.src.is_file():
|
|
128
|
-
output_file.mkdir(parents=True, exist_ok=True)
|
|
129
|
-
SecurePath(artifact.src).copy(output_file)
|
|
130
|
-
elif artifact.is_dir():
|
|
131
|
-
output_file.mkdir(parents=True, exist_ok=True)
|
|
132
|
+
# 2 get the artifacts list
|
|
133
|
+
artifacts = map_path_mapping_to_artifact(project_paths, self.model.artifacts)
|
|
134
|
+
from snowflake.cli.api.feature_flags import FeatureFlag
|
|
132
135
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
+
if FeatureFlag.ENABLE_SNOWPARK_GLOB_SUPPORT.is_enabled():
|
|
137
|
+
return zip_and_copy_artifacts_to_deploy(
|
|
138
|
+
artifacts, project_paths.bundle_root
|
|
139
|
+
)
|
|
140
|
+
else:
|
|
141
|
+
copied_files = []
|
|
142
|
+
for artifact in artifacts:
|
|
143
|
+
artifact.build()
|
|
144
|
+
copied_files.append(artifact.post_build_path)
|
|
145
|
+
return copied_files
|
|
136
146
|
|
|
137
147
|
def check_if_exists(
|
|
138
148
|
self, action_ctx: ActionContext
|
|
@@ -143,6 +153,9 @@ class SnowparkEntity(EntityBase[Generic[T]]):
|
|
|
143
153
|
except ProgrammingError:
|
|
144
154
|
return False
|
|
145
155
|
|
|
156
|
+
def deploy(self, mode: CreateMode = CreateMode.create, *args, **kwargs):
|
|
157
|
+
return self._execute_query(self.get_deploy_sql(mode))
|
|
158
|
+
|
|
146
159
|
def get_deploy_sql(self, mode: CreateMode):
|
|
147
160
|
query = [
|
|
148
161
|
f"{mode.value} {self.model.type.upper()} {self.identifier}",
|
|
@@ -14,37 +14,27 @@
|
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
import glob
|
|
18
18
|
from typing import List, Literal, Optional, Union
|
|
19
19
|
|
|
20
20
|
from pydantic import Field, field_validator
|
|
21
|
+
from snowflake.cli.api.feature_flags import FeatureFlag
|
|
21
22
|
from snowflake.cli.api.identifiers import FQN
|
|
22
23
|
from snowflake.cli.api.project.schemas.entities.common import (
|
|
23
|
-
|
|
24
|
+
EntityModelBaseWithArtifacts,
|
|
24
25
|
ExternalAccessBaseModel,
|
|
25
26
|
ImportsBaseModel,
|
|
27
|
+
PathMapping,
|
|
26
28
|
)
|
|
27
29
|
from snowflake.cli.api.project.schemas.updatable_model import (
|
|
28
30
|
DiscriminatorField,
|
|
29
|
-
UpdatableModel,
|
|
30
31
|
)
|
|
31
32
|
from snowflake.cli.api.project.schemas.v1.snowpark.argument import Argument
|
|
32
33
|
|
|
33
34
|
|
|
34
|
-
class
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
src: Path = Field(title="Source path (relative to project root)", default=None)
|
|
39
|
-
|
|
40
|
-
dest: Optional[str] = Field(
|
|
41
|
-
title="Destination path on stage",
|
|
42
|
-
description="Paths are relative to stage root; paths ending with a slash indicate that the destination is a directory which source files should be copied into.",
|
|
43
|
-
default=None,
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class SnowparkEntityModel(EntityModelBase, ExternalAccessBaseModel, ImportsBaseModel):
|
|
35
|
+
class SnowparkEntityModel(
|
|
36
|
+
EntityModelBaseWithArtifacts, ExternalAccessBaseModel, ImportsBaseModel
|
|
37
|
+
):
|
|
48
38
|
handler: str = Field(
|
|
49
39
|
title="Function’s or procedure’s implementation of the object inside source module",
|
|
50
40
|
examples=["functions.hello_function"],
|
|
@@ -59,17 +49,23 @@ class SnowparkEntityModel(EntityModelBase, ExternalAccessBaseModel, ImportsBaseM
|
|
|
59
49
|
title="Python version to use when executing ", default=None
|
|
60
50
|
)
|
|
61
51
|
stage: str = Field(title="Stage in which artifacts will be stored")
|
|
62
|
-
artifacts: List[Union[PathMapping, str]] = Field(title="List of required sources")
|
|
63
52
|
|
|
64
53
|
@field_validator("artifacts")
|
|
65
54
|
@classmethod
|
|
66
55
|
def _convert_artifacts(cls, artifacts: Union[dict, str]):
|
|
67
56
|
_artifacts = []
|
|
68
|
-
for
|
|
69
|
-
if
|
|
70
|
-
|
|
57
|
+
for artifact in artifacts:
|
|
58
|
+
if (
|
|
59
|
+
(isinstance(artifact, str) and glob.has_magic(artifact))
|
|
60
|
+
or (isinstance(artifact, PathMapping) and glob.has_magic(artifact.src))
|
|
61
|
+
) and FeatureFlag.ENABLE_SNOWPARK_GLOB_SUPPORT.is_disabled():
|
|
62
|
+
raise ValueError(
|
|
63
|
+
"If you want to use glob patterns in artifacts, you need to enable the Snowpark new build feature flag (enable_snowpark_glob_support=true)"
|
|
64
|
+
)
|
|
65
|
+
if isinstance(artifact, PathMapping):
|
|
66
|
+
_artifacts.append(artifact)
|
|
71
67
|
else:
|
|
72
|
-
_artifacts.append(PathMapping(src=
|
|
68
|
+
_artifacts.append(PathMapping(src=artifact))
|
|
73
69
|
return _artifacts
|
|
74
70
|
|
|
75
71
|
@field_validator("runtime")
|
|
@@ -79,14 +75,6 @@ class SnowparkEntityModel(EntityModelBase, ExternalAccessBaseModel, ImportsBaseM
|
|
|
79
75
|
return str(runtime_input)
|
|
80
76
|
return runtime_input
|
|
81
77
|
|
|
82
|
-
@field_validator("artifacts")
|
|
83
|
-
@classmethod
|
|
84
|
-
def validate_artifacts(cls, artifacts: List[Path]) -> List[Path]:
|
|
85
|
-
for artefact in artifacts:
|
|
86
|
-
if "*" in str(artefact):
|
|
87
|
-
raise ValueError("Glob patterns not supported for Snowpark artifacts.")
|
|
88
|
-
return artifacts
|
|
89
|
-
|
|
90
78
|
@property
|
|
91
79
|
def udf_sproc_identifier(self) -> UdfSprocIdentifier:
|
|
92
80
|
return UdfSprocIdentifier.from_definition(self)
|