snowflake-cli-labs 2.8.0rc1__py3-none-any.whl → 3.0.0rc0__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 → _app}/__main__.py +1 -1
- snowflake/cli/{app → _app}/cli_app.py +12 -12
- snowflake/cli/{app → _app}/commands_registration/builtin_plugins.py +13 -19
- snowflake/cli/{app → _app}/commands_registration/command_plugins_loader.py +9 -9
- snowflake/cli/{app → _app}/commands_registration/commands_registration_with_callbacks.py +4 -4
- snowflake/cli/{app → _app}/commands_registration/exception_logging.py +2 -2
- snowflake/cli/{app → _app}/commands_registration/typer_registration.py +2 -2
- snowflake/cli/{app → _app}/dev/docs/commands_docs_generator.py +30 -12
- snowflake/cli/{app → _app}/dev/docs/generator.py +3 -3
- snowflake/cli/{app → _app}/dev/docs/project_definition_docs_generator.py +4 -4
- snowflake/cli/{app → _app}/dev/docs/templates/usage.rst.jinja2 +14 -4
- snowflake/cli/{app → _app}/main_typer.py +2 -2
- snowflake/cli/{app → _app}/printing.py +2 -2
- snowflake/cli/{app → _app}/snow_connector.py +6 -6
- snowflake/cli/{app → _app}/telemetry.py +4 -5
- snowflake/cli/{plugins → _plugins}/connection/commands.py +22 -5
- snowflake/cli/_plugins/connection/plugin_spec.py +30 -0
- snowflake/cli/{plugins → _plugins}/connection/util.py +16 -0
- snowflake/cli/{plugins → _plugins}/cortex/commands.py +54 -49
- snowflake/cli/{plugins → _plugins}/cortex/constants.py +1 -1
- snowflake/cli/{plugins → _plugins}/cortex/manager.py +5 -5
- snowflake/cli/{plugins → _plugins}/cortex/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/git/commands.py +32 -20
- snowflake/cli/{plugins → _plugins}/git/manager.py +6 -5
- snowflake/cli/{plugins → _plugins}/git/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/init/commands.py +10 -6
- snowflake/cli/{plugins → _plugins}/init/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/nativeapp/artifacts.py +14 -0
- snowflake/cli/_plugins/nativeapp/bundle_context.py +31 -0
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/artifact_processor.py +3 -3
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/compiler.py +16 -18
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/setup/native_app_setup_processor.py +24 -28
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/extension_function_utils.py +4 -4
- snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/python_processor.py +20 -24
- snowflake/cli/{plugins → _plugins}/nativeapp/commands.py +171 -42
- snowflake/cli/{plugins → _plugins}/nativeapp/common_flags.py +1 -1
- snowflake/cli/{plugins → _plugins}/nativeapp/init.py +1 -1
- snowflake/cli/_plugins/nativeapp/manager.py +601 -0
- snowflake/cli/{plugins/connection → _plugins/nativeapp}/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/nativeapp/project_model.py +34 -11
- snowflake/cli/{plugins → _plugins}/nativeapp/run_processor.py +25 -23
- snowflake/cli/{plugins → _plugins}/nativeapp/teardown_processor.py +8 -8
- snowflake/cli/{plugins → _plugins}/nativeapp/v2_conversions/v2_to_v1_decorator.py +47 -28
- snowflake/cli/{plugins → _plugins}/nativeapp/version/commands.py +15 -12
- snowflake/cli/{plugins → _plugins}/nativeapp/version/version_processor.py +22 -20
- snowflake/cli/{plugins → _plugins}/notebook/commands.py +8 -6
- snowflake/cli/{plugins → _plugins}/notebook/manager.py +14 -14
- snowflake/cli/{plugins → _plugins}/notebook/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/notebook/types.py +0 -1
- snowflake/cli/{plugins → _plugins}/object/command_aliases.py +6 -5
- snowflake/cli/{plugins → _plugins}/object/commands.py +16 -10
- snowflake/cli/{plugins → _plugins}/object/manager.py +7 -6
- snowflake/cli/{plugins → _plugins}/object/plugin_spec.py +1 -1
- snowflake/cli/_plugins/snowpark/commands.py +510 -0
- snowflake/cli/_plugins/snowpark/common.py +252 -0
- snowflake/cli/{plugins → _plugins}/snowpark/models.py +0 -7
- snowflake/cli/{plugins → _plugins}/snowpark/package/anaconda_packages.py +1 -1
- snowflake/cli/{plugins → _plugins}/snowpark/package/commands.py +13 -74
- snowflake/cli/{plugins → _plugins}/snowpark/package/manager.py +4 -3
- snowflake/cli/{plugins → _plugins}/snowpark/package_utils.py +5 -5
- snowflake/cli/{plugins/nativeapp → _plugins/snowpark}/plugin_spec.py +1 -1
- snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +109 -0
- snowflake/cli/{plugins → _plugins}/snowpark/snowpark_shared.py +0 -36
- snowflake/cli/{plugins → _plugins}/snowpark/zipper.py +16 -8
- snowflake/cli/{plugins → _plugins}/spcs/__init__.py +5 -7
- snowflake/cli/{plugins → _plugins}/spcs/compute_pool/commands.py +29 -28
- snowflake/cli/{plugins → _plugins}/spcs/compute_pool/manager.py +3 -3
- snowflake/cli/{plugins → _plugins}/spcs/image_registry/commands.py +3 -3
- snowflake/cli/{plugins → _plugins}/spcs/image_repository/commands.py +25 -19
- snowflake/cli/{plugins → _plugins}/spcs/image_repository/manager.py +1 -1
- snowflake/cli/{plugins → _plugins}/spcs/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/spcs/services/commands.py +66 -32
- snowflake/cli/{plugins → _plugins}/spcs/services/manager.py +43 -5
- snowflake/cli/{plugins → _plugins}/sql/commands.py +19 -15
- snowflake/cli/{plugins → _plugins}/sql/manager.py +1 -1
- snowflake/cli/{plugins → _plugins}/sql/plugin_spec.py +1 -1
- snowflake/cli/{plugins → _plugins}/stage/commands.py +20 -17
- snowflake/cli/{plugins → _plugins}/stage/diff.py +1 -47
- snowflake/cli/{plugins → _plugins}/stage/manager.py +8 -6
- snowflake/cli/{plugins → _plugins}/stage/plugin_spec.py +1 -1
- snowflake/cli/_plugins/stage/utils.py +54 -0
- snowflake/cli/_plugins/streamlit/commands.py +242 -0
- snowflake/cli/{plugins → _plugins}/streamlit/manager.py +47 -70
- snowflake/cli/_plugins/streamlit/plugin_spec.py +30 -0
- snowflake/cli/_plugins/workspace/action_context.py +11 -0
- snowflake/cli/_plugins/workspace/commands.py +113 -0
- snowflake/cli/_plugins/workspace/manager.py +57 -0
- snowflake/cli/{plugins → _plugins}/workspace/plugin_spec.py +1 -1
- snowflake/cli/api/cli_global_context.py +34 -7
- snowflake/cli/api/commands/common.py +25 -0
- snowflake/cli/api/commands/decorators.py +4 -3
- snowflake/cli/api/commands/experimental_behaviour.py +2 -3
- snowflake/cli/api/commands/flags.py +73 -174
- snowflake/cli/api/commands/overrideable_parameter.py +143 -0
- snowflake/cli/api/commands/snow_typer.py +5 -4
- snowflake/cli/api/commands/typer_pre_execute.py +3 -3
- snowflake/cli/api/commands/utils.py +18 -0
- snowflake/cli/api/config.py +1 -1
- snowflake/cli/api/console/abc.py +5 -2
- snowflake/cli/api/entities/application_entity.py +12 -0
- snowflake/cli/api/entities/application_package_entity.py +260 -0
- snowflake/cli/api/entities/common.py +47 -0
- snowflake/cli/api/entities/snowpark_entity.py +29 -0
- snowflake/cli/api/entities/streamlit_entity.py +12 -0
- snowflake/cli/api/entities/utils.py +321 -0
- snowflake/cli/api/exceptions.py +19 -3
- snowflake/cli/api/feature_flags.py +2 -1
- snowflake/cli/api/identifiers.py +41 -9
- snowflake/cli/api/project/definition.py +13 -5
- snowflake/cli/api/project/definition_manager.py +12 -1
- snowflake/cli/api/project/project_verification.py +3 -3
- snowflake/cli/api/project/schemas/entities/{application_entity.py → application_entity_model.py} +21 -9
- snowflake/cli/api/project/schemas/entities/{application_package_entity.py → application_package_entity_model.py} +26 -15
- snowflake/cli/api/project/schemas/entities/common.py +80 -6
- snowflake/cli/api/project/schemas/entities/entities.py +38 -8
- snowflake/cli/api/project/schemas/entities/snowpark_entity.py +176 -0
- snowflake/cli/api/project/schemas/entities/streamlit_entity_model.py +73 -0
- snowflake/cli/api/project/schemas/identifier_model.py +10 -1
- snowflake/cli/api/project/schemas/native_app/application.py +8 -9
- snowflake/cli/api/project/schemas/native_app/package.py +7 -1
- snowflake/cli/api/project/schemas/project_definition.py +97 -23
- snowflake/cli/api/project/schemas/updatable_model.py +11 -3
- snowflake/cli/api/project/util.py +23 -6
- snowflake/cli/api/rendering/jinja.py +28 -8
- snowflake/cli/api/rendering/sql_templates.py +41 -12
- snowflake/cli/api/secure_path.py +3 -0
- snowflake/cli/api/sql_execution.py +35 -19
- snowflake/cli/api/utils/definition_rendering.py +14 -2
- {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0rc0.dist-info}/METADATA +12 -12
- snowflake_cli_labs-3.0.0rc0.dist-info/RECORD +234 -0
- snowflake_cli_labs-3.0.0rc0.dist-info/entry_points.txt +2 -0
- snowflake/cli/api/commands/project_initialisation.py +0 -65
- snowflake/cli/app/build_and_push.sh +0 -8
- snowflake/cli/plugins/nativeapp/manager.py +0 -823
- 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/commands.py +0 -548
- snowflake/cli/plugins/snowpark/common.py +0 -307
- snowflake/cli/plugins/snowpark/manager.py +0 -109
- snowflake/cli/plugins/snowpark/plugin_spec.py +0 -30
- snowflake/cli/plugins/snowpark/snowpark_package_paths.py +0 -65
- snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
- snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
- snowflake/cli/plugins/streamlit/commands.py +0 -186
- snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
- snowflake/cli/plugins/workspace/commands.py +0 -35
- 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/{app → _app}/__init__.py +0 -0
- /snowflake/cli/{app → _app}/api_impl/__init__.py +0 -0
- /snowflake/cli/{app → _app}/api_impl/plugin/__init__.py +0 -0
- /snowflake/cli/{app → _app}/api_impl/plugin/plugin_config_provider_impl.py +0 -0
- /snowflake/cli/{app → _app}/commands_registration/__init__.py +0 -0
- /snowflake/cli/{app → _app}/commands_registration/threadsafe.py +0 -0
- /snowflake/cli/{app → _app}/constants.py +0 -0
- /snowflake/cli/{app → _app}/dev/__init__.py +0 -0
- /snowflake/cli/{app → _app}/dev/commands_structure.py +0 -0
- /snowflake/cli/{app → _app}/dev/docs/__init__.py +0 -0
- /snowflake/cli/{app → _app}/dev/docs/project_definition_generate_json_schema.py +0 -0
- /snowflake/cli/{app → _app}/dev/docs/template_utils.py +0 -0
- /snowflake/cli/{app → _app}/dev/docs/templates/definition_description.rst.jinja2 +0 -0
- /snowflake/cli/{app → _app}/dev/docs/templates/overview.rst.jinja2 +0 -0
- /snowflake/cli/{app → _app}/dev/pycharm_remote_debug.py +0 -0
- /snowflake/cli/{app → _app}/loggers.py +0 -0
- /snowflake/cli/{plugins → _plugins}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/connection/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/cortex/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/cortex/types.py +0 -0
- /snowflake/cli/{plugins → _plugins}/git/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/init/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/sandbox.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/setup/setup_driver.py.source +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/models.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/constants.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/exceptions.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/feature_flags.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/policy.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/utils.py +0 -0
- /snowflake/cli/{plugins → _plugins}/nativeapp/version/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/notebook/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/notebook/exceptions.py +0 -0
- /snowflake/cli/{plugins → _plugins}/object/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/object/common.py +0 -0
- /snowflake/cli/{plugins → _plugins}/snowpark/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/snowpark/package/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/snowpark/package/utils.py +0 -0
- /snowflake/cli/{plugins → _plugins}/spcs/common.py +0 -0
- /snowflake/cli/{plugins → _plugins}/spcs/compute_pool/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/spcs/image_registry/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/spcs/image_registry/manager.py +0 -0
- /snowflake/cli/{plugins → _plugins}/spcs/image_repository/__init__.py +0 -0
- /snowflake/cli/{plugins/spcs/jobs → _plugins/spcs/services}/__init__.py +0 -0
- /snowflake/cli/{plugins/spcs/services → _plugins/sql}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/sql/snowsql_templating.py +0 -0
- /snowflake/cli/{plugins/sql → _plugins/stage}/__init__.py +0 -0
- /snowflake/cli/{plugins → _plugins}/stage/md5.py +0 -0
- /snowflake/cli/{plugins/stage → _plugins/streamlit}/__init__.py +0 -0
- /snowflake/cli/{plugins/streamlit → _plugins/workspace}/__init__.py +0 -0
- /snowflake/cli/{plugins/workspace → api/project/schemas/entities}/__init__.py +0 -0
- {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0rc0.dist-info}/WHEEL +0 -0
- {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0rc0.dist-info}/licenses/LICENSE +0 -0
|
@@ -15,22 +15,22 @@
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
from dataclasses import dataclass
|
|
18
|
-
from typing import Dict, Optional, Union
|
|
18
|
+
from typing import Any, Dict, List, Optional, Union
|
|
19
19
|
|
|
20
20
|
from packaging.version import Version
|
|
21
21
|
from pydantic import Field, ValidationError, field_validator, model_validator
|
|
22
22
|
from snowflake.cli.api.feature_flags import FeatureFlag
|
|
23
23
|
from snowflake.cli.api.project.errors import SchemaValidationError
|
|
24
|
-
from snowflake.cli.api.project.schemas.entities.
|
|
25
|
-
|
|
24
|
+
from snowflake.cli.api.project.schemas.entities.application_entity_model import (
|
|
25
|
+
ApplicationEntityModel,
|
|
26
26
|
)
|
|
27
27
|
from snowflake.cli.api.project.schemas.entities.common import (
|
|
28
28
|
DefaultsField,
|
|
29
29
|
TargetField,
|
|
30
30
|
)
|
|
31
31
|
from snowflake.cli.api.project.schemas.entities.entities import (
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
EntityModel,
|
|
33
|
+
v2_entity_model_types_map,
|
|
34
34
|
)
|
|
35
35
|
from snowflake.cli.api.project.schemas.native_app.native_app import (
|
|
36
36
|
NativeApp,
|
|
@@ -42,6 +42,8 @@ from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
|
|
|
42
42
|
from snowflake.cli.api.utils.types import Context
|
|
43
43
|
from typing_extensions import Annotated
|
|
44
44
|
|
|
45
|
+
AnnotatedEntity = Annotated[EntityModel, Field(discriminator="type")]
|
|
46
|
+
|
|
45
47
|
|
|
46
48
|
@dataclass
|
|
47
49
|
class ProjectProperties:
|
|
@@ -111,9 +113,7 @@ class DefinitionV11(DefinitionV10):
|
|
|
111
113
|
|
|
112
114
|
|
|
113
115
|
class DefinitionV20(_ProjectDefinitionBase):
|
|
114
|
-
entities: Dict[str,
|
|
115
|
-
title="Entity definitions."
|
|
116
|
-
)
|
|
116
|
+
entities: Dict[str, AnnotatedEntity] = Field(title="Entity definitions.")
|
|
117
117
|
|
|
118
118
|
@model_validator(mode="before")
|
|
119
119
|
@classmethod
|
|
@@ -123,34 +123,52 @@ class DefinitionV20(_ProjectDefinitionBase):
|
|
|
123
123
|
"""
|
|
124
124
|
if "defaults" in data and "entities" in data:
|
|
125
125
|
for key, entity in data["entities"].items():
|
|
126
|
-
|
|
127
|
-
if
|
|
126
|
+
entity_fields = get_allowed_fields_for_entity(entity)
|
|
127
|
+
if not entity_fields:
|
|
128
128
|
continue
|
|
129
|
-
entity_model = v2_entity_types_map[entity_type]
|
|
130
129
|
for default_key, default_value in data["defaults"].items():
|
|
131
|
-
if
|
|
132
|
-
default_key in entity_model.model_fields
|
|
133
|
-
and default_key not in entity
|
|
134
|
-
):
|
|
130
|
+
if default_key in entity_fields and default_key not in entity:
|
|
135
131
|
entity[default_key] = default_value
|
|
136
132
|
return data
|
|
137
133
|
|
|
138
134
|
@field_validator("entities", mode="after")
|
|
139
135
|
@classmethod
|
|
140
|
-
def
|
|
136
|
+
def validate_entities_identifiers(
|
|
137
|
+
cls, entities: Dict[str, EntityModel]
|
|
138
|
+
) -> Dict[str, EntityModel]:
|
|
139
|
+
for key, entity in entities.items():
|
|
140
|
+
entity.set_entity_id(key)
|
|
141
|
+
entity.validate_identifier()
|
|
142
|
+
return entities
|
|
143
|
+
|
|
144
|
+
@field_validator("entities", mode="after")
|
|
145
|
+
@classmethod
|
|
146
|
+
def validate_entities(
|
|
147
|
+
cls, entities: Dict[str, AnnotatedEntity]
|
|
148
|
+
) -> Dict[str, AnnotatedEntity]:
|
|
141
149
|
for key, entity in entities.items():
|
|
142
150
|
# TODO Automatically detect TargetFields to validate
|
|
143
|
-
if entity
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
cls._validate_target_field(target_key, target_type, entities)
|
|
151
|
+
if isinstance(entity, list):
|
|
152
|
+
for e in entity:
|
|
153
|
+
cls._validate_single_entity(e, entities)
|
|
154
|
+
else:
|
|
155
|
+
cls._validate_single_entity(entity, entities)
|
|
149
156
|
return entities
|
|
150
157
|
|
|
158
|
+
@classmethod
|
|
159
|
+
def _validate_single_entity(
|
|
160
|
+
cls, entity: EntityModel, entities: Dict[str, AnnotatedEntity]
|
|
161
|
+
):
|
|
162
|
+
if entity.type == ApplicationEntityModel.get_type():
|
|
163
|
+
if isinstance(entity.from_, TargetField):
|
|
164
|
+
target_key = entity.from_.target
|
|
165
|
+
target_object = entity.from_
|
|
166
|
+
target_type = target_object.get_type()
|
|
167
|
+
cls._validate_target_field(target_key, target_type, entities)
|
|
168
|
+
|
|
151
169
|
@classmethod
|
|
152
170
|
def _validate_target_field(
|
|
153
|
-
cls, target_key: str, target_type:
|
|
171
|
+
cls, target_key: str, target_type: EntityModel, entities: Dict[str, EntityModel]
|
|
154
172
|
):
|
|
155
173
|
if target_key not in entities:
|
|
156
174
|
raise ValueError(f"No such target: {target_key}")
|
|
@@ -172,6 +190,39 @@ class DefinitionV20(_ProjectDefinitionBase):
|
|
|
172
190
|
default=None,
|
|
173
191
|
)
|
|
174
192
|
|
|
193
|
+
mixins: Optional[Dict[str, Dict]] = Field(
|
|
194
|
+
title="Mixins to apply to entities",
|
|
195
|
+
default=None,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
@model_validator(mode="before")
|
|
199
|
+
@classmethod
|
|
200
|
+
def apply_mixins(cls, data: Dict) -> Dict:
|
|
201
|
+
"""
|
|
202
|
+
Applies mixins to those entities, whose meta field contains the mixin name.
|
|
203
|
+
"""
|
|
204
|
+
if "mixins" not in data or "entities" not in data:
|
|
205
|
+
return data
|
|
206
|
+
|
|
207
|
+
for entity in data["entities"].values():
|
|
208
|
+
entity_mixins = entity_mixins_to_list(
|
|
209
|
+
entity.get("meta", {}).get("use_mixins")
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
entity_fields = get_allowed_fields_for_entity(entity)
|
|
213
|
+
if entity_fields and entity_mixins:
|
|
214
|
+
for mixin_name in entity_mixins:
|
|
215
|
+
if mixin_name in data["mixins"]:
|
|
216
|
+
for key, value in data["mixins"][mixin_name].items():
|
|
217
|
+
if key in entity_fields:
|
|
218
|
+
entity[key] = value
|
|
219
|
+
else:
|
|
220
|
+
raise ValueError(f"Mixin {mixin_name} not found in mixins")
|
|
221
|
+
return data
|
|
222
|
+
|
|
223
|
+
def get_entities_by_type(self, entity_type: str):
|
|
224
|
+
return {i: e for i, e in self.entities.items() if e.get_type() == entity_type}
|
|
225
|
+
|
|
175
226
|
|
|
176
227
|
def build_project_definition(**data) -> ProjectDefinition:
|
|
177
228
|
"""
|
|
@@ -197,3 +248,26 @@ def get_version_map():
|
|
|
197
248
|
if FeatureFlag.ENABLE_PROJECT_DEFINITION_V2.is_enabled():
|
|
198
249
|
version_map["2"] = DefinitionV20
|
|
199
250
|
return version_map
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def entity_mixins_to_list(entity_mixins: Optional[str | List[str]]) -> List[str]:
|
|
254
|
+
"""
|
|
255
|
+
Convert an optional string or a list of strings to a list of strings.
|
|
256
|
+
"""
|
|
257
|
+
if entity_mixins is None:
|
|
258
|
+
return []
|
|
259
|
+
if isinstance(entity_mixins, str):
|
|
260
|
+
return [entity_mixins]
|
|
261
|
+
return entity_mixins
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def get_allowed_fields_for_entity(entity: Dict[str, Any]) -> List[str]:
|
|
265
|
+
"""
|
|
266
|
+
Get the allowed fields for the given entity.
|
|
267
|
+
"""
|
|
268
|
+
entity_type = entity.get("type")
|
|
269
|
+
if entity_type not in v2_entity_model_types_map:
|
|
270
|
+
return []
|
|
271
|
+
|
|
272
|
+
entity_model = v2_entity_model_types_map[entity_type]
|
|
273
|
+
return entity_model.model_fields
|
|
@@ -117,6 +117,7 @@ class UpdatableModel(BaseModel):
|
|
|
117
117
|
# all the values of the class attributes. We go in reverse order so that
|
|
118
118
|
# values in subclasses overrides values from parent classes in case of field overrides.
|
|
119
119
|
|
|
120
|
+
private_attrs = set()
|
|
120
121
|
for class_ in reversed(cls.__mro__):
|
|
121
122
|
class_dict = class_.__dict__
|
|
122
123
|
field_annotations.update(class_dict.get("__annotations__", {}))
|
|
@@ -128,10 +129,15 @@ class UpdatableModel(BaseModel):
|
|
|
128
129
|
else:
|
|
129
130
|
# If Pydantic did not process this class yet, get the values from class_dict directly
|
|
130
131
|
field_values.update(class_dict)
|
|
132
|
+
for pa in class_dict.get("__private_attributes__", []):
|
|
133
|
+
private_attrs.add(pa)
|
|
131
134
|
|
|
132
135
|
# Add Pydantic validation wrapper around all fields except `DiscriminatorField`s
|
|
133
136
|
for field_name in field_annotations:
|
|
134
|
-
if
|
|
137
|
+
if field_name in private_attrs:
|
|
138
|
+
continue
|
|
139
|
+
field = field_values.get(field_name)
|
|
140
|
+
if not cls._is_entity_type_field(field):
|
|
135
141
|
cls._add_validator(field_name)
|
|
136
142
|
|
|
137
143
|
@classmethod
|
|
@@ -154,7 +160,8 @@ class UpdatableModel(BaseModel):
|
|
|
154
160
|
|
|
155
161
|
setattr(
|
|
156
162
|
cls,
|
|
157
|
-
|
|
163
|
+
# Unique name so that subclasses get a unique instance of this validator
|
|
164
|
+
f"_{cls.__module__}.{cls.__name__}_validate_{field_name}",
|
|
158
165
|
field_validator(field_name, mode="wrap")(validator_skipping_templated_str),
|
|
159
166
|
)
|
|
160
167
|
|
|
@@ -187,7 +194,8 @@ def DiscriminatorField(*args, **kwargs): # noqa N802
|
|
|
187
194
|
When this `DiscriminatorField` is used on a pydantic attribute,
|
|
188
195
|
we will not allow templating on it.
|
|
189
196
|
"""
|
|
190
|
-
|
|
197
|
+
extra = dict(is_discriminator_field=True)
|
|
198
|
+
return Field(json_schema_extra=extra, *args, **kwargs)
|
|
191
199
|
|
|
192
200
|
|
|
193
201
|
def IdentifierField(*args, **kwargs): # noqa N802
|
|
@@ -34,6 +34,9 @@ UNQUOTED_IDENTIFIER_REGEX = r"([a-zA-Z_])([a-zA-Z0-9_$]{0,254})"
|
|
|
34
34
|
QUOTED_IDENTIFIER_REGEX = r'"((""|[^"]){0,255})"'
|
|
35
35
|
VALID_IDENTIFIER_REGEX = f"(?:{UNQUOTED_IDENTIFIER_REGEX}|{QUOTED_IDENTIFIER_REGEX})"
|
|
36
36
|
|
|
37
|
+
# An env var that is used to suffix the names of some account-level resources
|
|
38
|
+
TEST_RESOURCE_SUFFIX_VAR = "SNOWFLAKE_CLI_TEST_RESOURCE_SUFFIX"
|
|
39
|
+
|
|
37
40
|
|
|
38
41
|
def encode_uri_component(s: str) -> str:
|
|
39
42
|
"""
|
|
@@ -191,12 +194,6 @@ def extract_schema(qualified_name: str):
|
|
|
191
194
|
return None
|
|
192
195
|
|
|
193
196
|
|
|
194
|
-
def generate_user_env(username: str) -> dict:
|
|
195
|
-
return {
|
|
196
|
-
"USER": username,
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
|
|
200
197
|
def first_set_env(*keys: str):
|
|
201
198
|
for k in keys:
|
|
202
199
|
v = os.getenv(k)
|
|
@@ -259,3 +256,23 @@ def identifier_to_show_like_pattern(identifier: str) -> str:
|
|
|
259
256
|
matching this identifier
|
|
260
257
|
"""
|
|
261
258
|
return f"'{escape_like_pattern(unquote_identifier(identifier))}'"
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def append_test_resource_suffix(identifier: str) -> str:
|
|
262
|
+
"""
|
|
263
|
+
Append a suffix that should be added to specified account-level resources.
|
|
264
|
+
|
|
265
|
+
This is an internal concern that is currently only used in tests
|
|
266
|
+
to isolate concurrent runs and to add the test name to resources.
|
|
267
|
+
"""
|
|
268
|
+
suffix = os.environ.get(TEST_RESOURCE_SUFFIX_VAR, "")
|
|
269
|
+
if identifier_to_str(identifier).endswith(identifier_to_str(suffix)):
|
|
270
|
+
# If the suffix has already been added, don't add it again
|
|
271
|
+
return identifier
|
|
272
|
+
if is_valid_quoted_identifier(identifier) or is_valid_quoted_identifier(suffix):
|
|
273
|
+
# If either identifier is already quoted, use concat_identifier
|
|
274
|
+
# to add the suffix inside the quotes
|
|
275
|
+
return concat_identifiers([identifier, suffix])
|
|
276
|
+
# Otherwise just append the string, don't add quotes
|
|
277
|
+
# in case the user doesn't want them
|
|
278
|
+
return f"{identifier}{suffix}"
|
|
@@ -17,7 +17,7 @@ from __future__ import annotations
|
|
|
17
17
|
|
|
18
18
|
from pathlib import Path
|
|
19
19
|
from textwrap import dedent
|
|
20
|
-
from typing import Dict, Optional
|
|
20
|
+
from typing import Any, Dict, Optional
|
|
21
21
|
|
|
22
22
|
import jinja2
|
|
23
23
|
from jinja2 import Environment, StrictUndefined, loaders
|
|
@@ -82,8 +82,32 @@ class IgnoreAttrEnvironment(Environment):
|
|
|
82
82
|
return self.undefined(obj=obj, name=argument)
|
|
83
83
|
|
|
84
84
|
|
|
85
|
+
def _get_jinja_env(loader: Optional[loaders.BaseLoader] = None) -> Environment:
|
|
86
|
+
return env_bootstrap(
|
|
87
|
+
IgnoreAttrEnvironment(
|
|
88
|
+
loader=loader or loaders.BaseLoader(),
|
|
89
|
+
keep_trailing_newline=True,
|
|
90
|
+
undefined=StrictUndefined,
|
|
91
|
+
)
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def jinja_render_from_str(template_content: str, data: Dict[str, Any]) -> str:
|
|
96
|
+
"""
|
|
97
|
+
Renders a jinja template and outputs either the rendered contents as string or writes to a file.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
template_content (str): template contents
|
|
101
|
+
data (dict): A dictionary of jinja variables and their actual values
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
None if file path is provided, else returns the rendered string.
|
|
105
|
+
"""
|
|
106
|
+
return _get_jinja_env().from_string(template_content).render(data)
|
|
107
|
+
|
|
108
|
+
|
|
85
109
|
def jinja_render_from_file(
|
|
86
|
-
template_path: Path, data: Dict, output_file_path: Optional[Path] = None
|
|
110
|
+
template_path: Path, data: Dict[str, Any], output_file_path: Optional[Path] = None
|
|
87
111
|
) -> Optional[str]:
|
|
88
112
|
"""
|
|
89
113
|
Renders a jinja template and outputs either the rendered contents as string or writes to a file.
|
|
@@ -96,12 +120,8 @@ def jinja_render_from_file(
|
|
|
96
120
|
Returns:
|
|
97
121
|
None if file path is provided, else returns the rendered string.
|
|
98
122
|
"""
|
|
99
|
-
env =
|
|
100
|
-
|
|
101
|
-
loader=loaders.FileSystemLoader(template_path.parent),
|
|
102
|
-
keep_trailing_newline=True,
|
|
103
|
-
undefined=StrictUndefined,
|
|
104
|
-
)
|
|
123
|
+
env = _get_jinja_env(
|
|
124
|
+
loader=loaders.FileSystemLoader(template_path.parent.as_posix())
|
|
105
125
|
)
|
|
106
126
|
loaded_template = env.get_template(template_path.name)
|
|
107
127
|
rendered_result = loaded_template.render(**data)
|
|
@@ -14,11 +14,13 @@
|
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
|
-
from typing import Dict
|
|
17
|
+
from typing import Dict
|
|
18
18
|
|
|
19
19
|
from click import ClickException
|
|
20
|
-
from jinja2 import StrictUndefined, loaders
|
|
21
|
-
from snowflake.cli.api.cli_global_context import
|
|
20
|
+
from jinja2 import Environment, StrictUndefined, loaders, meta
|
|
21
|
+
from snowflake.cli.api.cli_global_context import get_cli_context
|
|
22
|
+
from snowflake.cli.api.console.console import cli_console
|
|
23
|
+
from snowflake.cli.api.exceptions import InvalidTemplate
|
|
22
24
|
from snowflake.cli.api.rendering.jinja import (
|
|
23
25
|
CONTEXT_KEY,
|
|
24
26
|
FUNCTION_KEY,
|
|
@@ -26,26 +28,52 @@ from snowflake.cli.api.rendering.jinja import (
|
|
|
26
28
|
env_bootstrap,
|
|
27
29
|
)
|
|
28
30
|
|
|
29
|
-
_SQL_TEMPLATE_START = "
|
|
30
|
-
_SQL_TEMPLATE_END = "
|
|
31
|
+
_SQL_TEMPLATE_START = "<%"
|
|
32
|
+
_SQL_TEMPLATE_END = "%>"
|
|
33
|
+
_OLD_SQL_TEMPLATE_START = "&{"
|
|
34
|
+
_OLD_SQL_TEMPLATE_END = "}"
|
|
31
35
|
RESERVED_KEYS = [CONTEXT_KEY, FUNCTION_KEY]
|
|
32
36
|
|
|
33
37
|
|
|
34
|
-
def
|
|
38
|
+
def _get_sql_jinja_env(template_start: str, template_end: str) -> Environment:
|
|
35
39
|
_random_block = "___very___unique___block___to___disable___logic___blocks___"
|
|
36
40
|
return env_bootstrap(
|
|
37
41
|
IgnoreAttrEnvironment(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
variable_end_string=_SQL_TEMPLATE_END,
|
|
42
|
+
variable_start_string=template_start,
|
|
43
|
+
variable_end_string=template_end,
|
|
44
|
+
loader=loaders.BaseLoader(),
|
|
42
45
|
block_start_string=_random_block,
|
|
43
46
|
block_end_string=_random_block,
|
|
47
|
+
keep_trailing_newline=True,
|
|
44
48
|
undefined=StrictUndefined,
|
|
45
49
|
)
|
|
46
50
|
)
|
|
47
51
|
|
|
48
52
|
|
|
53
|
+
def _does_template_have_env_syntax(env: Environment, template_content: str) -> bool:
|
|
54
|
+
template = env.parse(template_content)
|
|
55
|
+
return bool(meta.find_undeclared_variables(template))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def choose_sql_jinja_env_based_on_template_syntax(template_content: str) -> Environment:
|
|
59
|
+
old_syntax_env = _get_sql_jinja_env(_OLD_SQL_TEMPLATE_START, _OLD_SQL_TEMPLATE_END)
|
|
60
|
+
new_syntax_env = _get_sql_jinja_env(_SQL_TEMPLATE_START, _SQL_TEMPLATE_END)
|
|
61
|
+
has_old_syntax = _does_template_have_env_syntax(old_syntax_env, template_content)
|
|
62
|
+
has_new_syntax = _does_template_have_env_syntax(new_syntax_env, template_content)
|
|
63
|
+
if has_old_syntax and has_new_syntax:
|
|
64
|
+
raise InvalidTemplate(
|
|
65
|
+
f"The SQL query mixes {_OLD_SQL_TEMPLATE_START} ... {_OLD_SQL_TEMPLATE_END} syntax"
|
|
66
|
+
f" and {_SQL_TEMPLATE_START} ... {_SQL_TEMPLATE_END} syntax."
|
|
67
|
+
)
|
|
68
|
+
if has_old_syntax:
|
|
69
|
+
cli_console.warning(
|
|
70
|
+
f"Warning: {_OLD_SQL_TEMPLATE_START} ... {_OLD_SQL_TEMPLATE_END} syntax is deprecated."
|
|
71
|
+
f" Use {_SQL_TEMPLATE_START} ... {_SQL_TEMPLATE_END} syntax instead."
|
|
72
|
+
)
|
|
73
|
+
return old_syntax_env
|
|
74
|
+
return new_syntax_env
|
|
75
|
+
|
|
76
|
+
|
|
49
77
|
def snowflake_sql_jinja_render(content: str, data: Dict | None = None) -> str:
|
|
50
78
|
data = data or {}
|
|
51
79
|
|
|
@@ -55,6 +83,7 @@ def snowflake_sql_jinja_render(content: str, data: Dict | None = None) -> str:
|
|
|
55
83
|
f"{reserved_key} in user defined data. The `{reserved_key}` variable is reserved for CLI usage."
|
|
56
84
|
)
|
|
57
85
|
|
|
58
|
-
context_data =
|
|
86
|
+
context_data = get_cli_context().template_context
|
|
59
87
|
context_data.update(data)
|
|
60
|
-
|
|
88
|
+
env = choose_sql_jinja_env_based_on_template_syntax(content)
|
|
89
|
+
return env.from_string(content).render(context_data)
|
snowflake/cli/api/secure_path.py
CHANGED
|
@@ -349,6 +349,9 @@ class SecurePath:
|
|
|
349
349
|
):
|
|
350
350
|
raise FileTooLargeError(self._path.resolve(), size_limit_in_mb)
|
|
351
351
|
|
|
352
|
+
def rename(self, new_name: Union[str | Path]):
|
|
353
|
+
self._path.rename(new_name)
|
|
354
|
+
|
|
352
355
|
|
|
353
356
|
def _raise_file_exists_error(path: Path):
|
|
354
357
|
raise FileExistsError(errno.EEXIST, os.strerror(errno.EEXIST), path)
|
|
@@ -21,7 +21,7 @@ from io import StringIO
|
|
|
21
21
|
from textwrap import dedent
|
|
22
22
|
from typing import Iterable, Optional, Tuple
|
|
23
23
|
|
|
24
|
-
from snowflake.cli.api.cli_global_context import
|
|
24
|
+
from snowflake.cli.api.cli_global_context import get_cli_context
|
|
25
25
|
from snowflake.cli.api.console import cli_console
|
|
26
26
|
from snowflake.cli.api.constants import ObjectType
|
|
27
27
|
from snowflake.cli.api.exceptions import (
|
|
@@ -35,27 +35,21 @@ from snowflake.cli.api.project.util import (
|
|
|
35
35
|
unquote_identifier,
|
|
36
36
|
)
|
|
37
37
|
from snowflake.cli.api.utils.cursor import find_first_row
|
|
38
|
+
from snowflake.connector import SnowflakeConnection
|
|
38
39
|
from snowflake.connector.cursor import DictCursor, SnowflakeCursor
|
|
39
40
|
from snowflake.connector.errors import ProgrammingError
|
|
40
41
|
|
|
41
42
|
|
|
42
|
-
class
|
|
43
|
-
def __init__(self):
|
|
43
|
+
class SqlExecutor:
|
|
44
|
+
def __init__(self, connection: SnowflakeConnection | None = None):
|
|
44
45
|
self._snowpark_session = None
|
|
46
|
+
self._connection = connection
|
|
45
47
|
|
|
46
48
|
@property
|
|
47
|
-
def _conn(self):
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def snowpark_session(self):
|
|
52
|
-
if not self._snowpark_session:
|
|
53
|
-
from snowflake.snowpark.session import Session
|
|
54
|
-
|
|
55
|
-
self._snowpark_session = Session.builder.configs(
|
|
56
|
-
{"connection": self._conn}
|
|
57
|
-
).create()
|
|
58
|
-
return self._snowpark_session
|
|
49
|
+
def _conn(self) -> SnowflakeConnection:
|
|
50
|
+
if self._connection:
|
|
51
|
+
return self._connection
|
|
52
|
+
return get_cli_context().connection
|
|
59
53
|
|
|
60
54
|
@cached_property
|
|
61
55
|
def _log(self):
|
|
@@ -88,6 +82,12 @@ class SqlExecutionMixin:
|
|
|
88
82
|
def _execute_queries(self, queries: str, **kwargs):
|
|
89
83
|
return list(self._execute_string(dedent(queries), **kwargs))
|
|
90
84
|
|
|
85
|
+
def execute_query(self, query: str, **kwargs):
|
|
86
|
+
return self._execute_query(query, **kwargs)
|
|
87
|
+
|
|
88
|
+
def execute_queries(self, queries: str, **kwargs):
|
|
89
|
+
return self._execute_queries(queries, **kwargs)
|
|
90
|
+
|
|
91
91
|
def use(self, object_type: ObjectType, name: str):
|
|
92
92
|
try:
|
|
93
93
|
self._execute_query(f"use {object_type.value.sf_name} {name}")
|
|
@@ -147,11 +147,11 @@ class SqlExecutionMixin:
|
|
|
147
147
|
self.use(object_type=ObjectType.WAREHOUSE, name=prev_wh)
|
|
148
148
|
|
|
149
149
|
def create_password_secret(
|
|
150
|
-
self, name:
|
|
150
|
+
self, name: FQN, username: str, password: str
|
|
151
151
|
) -> SnowflakeCursor:
|
|
152
152
|
return self._execute_query(
|
|
153
153
|
f"""
|
|
154
|
-
create secret {name}
|
|
154
|
+
create secret {name.sql_identifier}
|
|
155
155
|
type = password
|
|
156
156
|
username = '{username}'
|
|
157
157
|
password = '{password}'
|
|
@@ -159,11 +159,11 @@ class SqlExecutionMixin:
|
|
|
159
159
|
)
|
|
160
160
|
|
|
161
161
|
def create_api_integration(
|
|
162
|
-
self, name:
|
|
162
|
+
self, name: FQN, api_provider: str, allowed_prefix: str, secret: Optional[str]
|
|
163
163
|
) -> SnowflakeCursor:
|
|
164
164
|
return self._execute_query(
|
|
165
165
|
f"""
|
|
166
|
-
create api integration {name}
|
|
166
|
+
create api integration {name.sql_identifier}
|
|
167
167
|
api_provider = {api_provider}
|
|
168
168
|
api_allowed_prefixes = ('{allowed_prefix}')
|
|
169
169
|
allowed_authentication_secrets = ({secret if secret else ''})
|
|
@@ -254,6 +254,22 @@ class SqlExecutionMixin:
|
|
|
254
254
|
return show_obj_row
|
|
255
255
|
|
|
256
256
|
|
|
257
|
+
class SqlExecutionMixin(SqlExecutor):
|
|
258
|
+
def __init__(self, *args, **kwargs):
|
|
259
|
+
super().__init__(*args, **kwargs)
|
|
260
|
+
self._snowpark_session = None
|
|
261
|
+
|
|
262
|
+
@property
|
|
263
|
+
def snowpark_session(self):
|
|
264
|
+
if not self._snowpark_session:
|
|
265
|
+
from snowflake.snowpark.session import Session
|
|
266
|
+
|
|
267
|
+
self._snowpark_session = Session.builder.configs(
|
|
268
|
+
{"connection": self._conn}
|
|
269
|
+
).create()
|
|
270
|
+
return self._snowpark_session
|
|
271
|
+
|
|
272
|
+
|
|
257
273
|
class VerboseCursor(SnowflakeCursor):
|
|
258
274
|
def execute(self, command: str, *args, **kwargs):
|
|
259
275
|
cli_console.message(command)
|
|
@@ -26,7 +26,7 @@ from snowflake.cli.api.project.schemas.project_definition import (
|
|
|
26
26
|
build_project_definition,
|
|
27
27
|
)
|
|
28
28
|
from snowflake.cli.api.project.schemas.updatable_model import context
|
|
29
|
-
from snowflake.cli.api.rendering.jinja import CONTEXT_KEY
|
|
29
|
+
from snowflake.cli.api.rendering.jinja import CONTEXT_KEY, FUNCTION_KEY
|
|
30
30
|
from snowflake.cli.api.rendering.project_definition_templates import (
|
|
31
31
|
get_project_definition_cli_jinja_env,
|
|
32
32
|
)
|
|
@@ -344,7 +344,7 @@ def render_definition_template(
|
|
|
344
344
|
_validate_env_section(definition.get("env", {}))
|
|
345
345
|
|
|
346
346
|
# add available templating functions
|
|
347
|
-
project_context[
|
|
347
|
+
project_context[FUNCTION_KEY] = get_templating_functions()
|
|
348
348
|
|
|
349
349
|
referenced_vars = _get_referenced_vars_in_definition(template_env, definition)
|
|
350
350
|
|
|
@@ -374,10 +374,22 @@ def render_definition_template(
|
|
|
374
374
|
)
|
|
375
375
|
|
|
376
376
|
project_definition = build_project_definition(**definition)
|
|
377
|
+
|
|
378
|
+
# Use the values originally provided by the user as the template context
|
|
379
|
+
# This intentionally doesn't reflect any field changes made by
|
|
380
|
+
# validators, to minimize user surprise when templating values
|
|
377
381
|
project_context[CONTEXT_KEY] = definition
|
|
382
|
+
|
|
378
383
|
# Use `ProjectEnvironment` in project context in order to
|
|
379
384
|
# handle env variables overrides from OS env and from CLI arguments.
|
|
380
385
|
project_context[CONTEXT_KEY]["env"] = ProjectEnvironment(
|
|
381
386
|
default_env=project_context[CONTEXT_KEY].get("env"), override_env=override_env
|
|
382
387
|
)
|
|
383
388
|
return ProjectProperties(project_definition, project_context)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def raw_project_properties(definition: Definition) -> ProjectProperties:
|
|
392
|
+
"""
|
|
393
|
+
Returns the raw project definition data without any templating.
|
|
394
|
+
"""
|
|
395
|
+
return ProjectProperties(build_project_definition(**definition), {})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: snowflake-cli-labs
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0rc0
|
|
4
4
|
Summary: Snowflake CLI
|
|
5
5
|
Project-URL: Source code, https://github.com/snowflakedb/snowflake-cli
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/snowflakedb/snowflake-cli/issues
|
|
@@ -216,7 +216,7 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
|
216
216
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
217
217
|
Classifier: Programming Language :: SQL
|
|
218
218
|
Classifier: Topic :: Database
|
|
219
|
-
Requires-Python: >=3.
|
|
219
|
+
Requires-Python: >=3.10
|
|
220
220
|
Requires-Dist: gitpython==3.1.43
|
|
221
221
|
Requires-Dist: jinja2==3.1.4
|
|
222
222
|
Requires-Dist: packaging
|
|
@@ -225,20 +225,20 @@ Requires-Dist: pluggy==1.5.0
|
|
|
225
225
|
Requires-Dist: pydantic==2.8.2
|
|
226
226
|
Requires-Dist: pyyaml==6.0.1
|
|
227
227
|
Requires-Dist: requests==2.32.3
|
|
228
|
-
Requires-Dist: requirements-parser==0.
|
|
228
|
+
Requires-Dist: requirements-parser==0.10.2
|
|
229
229
|
Requires-Dist: rich==13.7.1
|
|
230
230
|
Requires-Dist: setuptools==70.3.0
|
|
231
|
-
Requires-Dist: snowflake-connector-python[secure-local-storage]==3.
|
|
231
|
+
Requires-Dist: snowflake-connector-python[secure-local-storage]==3.12.0
|
|
232
232
|
Requires-Dist: snowflake-core==0.8.0; python_version < '3.12'
|
|
233
233
|
Requires-Dist: snowflake-snowpark-python>=1.15.0; python_version < '3.12'
|
|
234
|
-
Requires-Dist: tomlkit==0.13.
|
|
235
|
-
Requires-Dist: typer==0.12.
|
|
234
|
+
Requires-Dist: tomlkit==0.13.2
|
|
235
|
+
Requires-Dist: typer==0.12.4
|
|
236
236
|
Requires-Dist: urllib3<2.3,>=1.24.3
|
|
237
237
|
Provides-Extra: development
|
|
238
|
-
Requires-Dist: coverage==7.6.
|
|
238
|
+
Requires-Dist: coverage==7.6.1; extra == 'development'
|
|
239
239
|
Requires-Dist: pre-commit>=3.5.0; extra == 'development'
|
|
240
240
|
Requires-Dist: pytest-randomly==3.15.0; extra == 'development'
|
|
241
|
-
Requires-Dist: pytest==8.3.
|
|
241
|
+
Requires-Dist: pytest==8.3.2; extra == 'development'
|
|
242
242
|
Requires-Dist: syrupy==4.6.1; extra == 'development'
|
|
243
243
|
Description-Content-Type: text/markdown
|
|
244
244
|
|
|
@@ -282,12 +282,12 @@ Cheatsheet: https://github.com/Snowflake-Labs/sf-cheatsheets/blob/main/snowflake
|
|
|
282
282
|
|
|
283
283
|
## Install Snowflake CLI
|
|
284
284
|
|
|
285
|
-
### Install with
|
|
285
|
+
### Install with pipx (PyPi)
|
|
286
286
|
|
|
287
|
-
Requires Python >= 3.
|
|
287
|
+
We recommend installing Snowflake CLI in isolated environment using [pipx](https://pipx.pypa.io/stable/). Requires Python >= 3.10
|
|
288
288
|
|
|
289
289
|
```bash
|
|
290
|
-
|
|
290
|
+
pipx install snowflake-cli-labs
|
|
291
291
|
snow --help
|
|
292
292
|
```
|
|
293
293
|
|
|
@@ -303,7 +303,7 @@ snow --help
|
|
|
303
303
|
|
|
304
304
|
### Install from source
|
|
305
305
|
|
|
306
|
-
Requires Python >= 3.
|
|
306
|
+
Requires Python >= 3.10 and git
|
|
307
307
|
|
|
308
308
|
```bash
|
|
309
309
|
git clone https://github.com/snowflakedb/snowflake-cli
|