snowflake-cli-labs 3.0.0rc2__py3-none-any.whl → 3.0.0rc4__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.
Files changed (88) hide show
  1. snowflake/cli/__about__.py +1 -1
  2. snowflake/cli/_app/commands_registration/builtin_plugins.py +2 -0
  3. snowflake/cli/_app/secret.py +9 -0
  4. snowflake/cli/_app/snow_connector.py +39 -27
  5. snowflake/cli/_app/telemetry.py +28 -0
  6. snowflake/cli/_plugins/connection/commands.py +9 -4
  7. snowflake/cli/_plugins/git/manager.py +53 -7
  8. snowflake/cli/_plugins/helpers/commands.py +61 -0
  9. snowflake/cli/{api/project/schemas/snowpark/__init__.py → _plugins/helpers/plugin_spec.py} +17 -0
  10. snowflake/cli/_plugins/nativeapp/artifacts.py +10 -9
  11. snowflake/cli/_plugins/nativeapp/bundle_context.py +1 -1
  12. snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +1 -1
  13. snowflake/cli/_plugins/nativeapp/codegen/compiler.py +6 -1
  14. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +1 -1
  15. snowflake/cli/_plugins/nativeapp/codegen/snowpark/extension_function_utils.py +1 -1
  16. snowflake/cli/_plugins/nativeapp/codegen/snowpark/models.py +1 -1
  17. snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +5 -1
  18. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +4 -1
  19. snowflake/cli/_plugins/nativeapp/commands.py +87 -96
  20. snowflake/cli/_plugins/nativeapp/entities/__init__.py +0 -0
  21. snowflake/cli/{api/entities/application_entity.py → _plugins/nativeapp/entities/application.py} +264 -83
  22. snowflake/cli/_plugins/nativeapp/entities/application_package.py +1392 -0
  23. snowflake/cli/_plugins/nativeapp/exceptions.py +0 -9
  24. snowflake/cli/_plugins/nativeapp/manager.py +69 -185
  25. snowflake/cli/_plugins/nativeapp/policy.py +3 -0
  26. snowflake/cli/_plugins/nativeapp/project_model.py +2 -2
  27. snowflake/cli/_plugins/nativeapp/run_processor.py +17 -20
  28. snowflake/cli/_plugins/nativeapp/same_account_install_method.py +0 -4
  29. snowflake/cli/_plugins/nativeapp/teardown_processor.py +4 -6
  30. snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +122 -88
  31. snowflake/cli/_plugins/nativeapp/version/commands.py +7 -39
  32. snowflake/cli/_plugins/nativeapp/version/version_processor.py +46 -312
  33. snowflake/cli/_plugins/object/manager.py +36 -15
  34. snowflake/cli/_plugins/snowpark/commands.py +4 -4
  35. snowflake/cli/_plugins/snowpark/common.py +4 -4
  36. snowflake/cli/{api/entities → _plugins/snowpark}/snowpark_entity.py +2 -2
  37. snowflake/cli/{api/project/schemas/entities/snowpark_entity.py → _plugins/snowpark/snowpark_entity_model.py} +3 -6
  38. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +1 -1
  39. snowflake/cli/_plugins/stage/manager.py +9 -4
  40. snowflake/cli/_plugins/streamlit/commands.py +15 -3
  41. snowflake/cli/_plugins/streamlit/manager.py +12 -4
  42. snowflake/cli/{api/entities → _plugins/streamlit}/streamlit_entity.py +2 -2
  43. snowflake/cli/{api/project/schemas/entities → _plugins/streamlit}/streamlit_entity_model.py +5 -12
  44. snowflake/cli/_plugins/workspace/commands.py +116 -36
  45. snowflake/cli/_plugins/workspace/plugin_spec.py +1 -1
  46. snowflake/cli/api/cli_global_context.py +7 -0
  47. snowflake/cli/api/commands/decorators.py +14 -0
  48. snowflake/cli/api/commands/flags.py +18 -0
  49. snowflake/cli/api/commands/snow_typer.py +1 -1
  50. snowflake/cli/api/config.py +25 -6
  51. snowflake/cli/api/connections.py +3 -1
  52. snowflake/cli/api/entities/common.py +4 -0
  53. snowflake/cli/api/entities/utils.py +3 -14
  54. snowflake/cli/api/errno.py +1 -0
  55. snowflake/cli/api/identifiers.py +4 -3
  56. snowflake/cli/api/metrics.py +92 -0
  57. snowflake/cli/api/project/definition_conversion.py +61 -18
  58. snowflake/cli/api/project/schemas/entities/common.py +17 -4
  59. snowflake/cli/api/project/schemas/entities/entities.py +11 -10
  60. snowflake/cli/api/project/schemas/project_definition.py +5 -7
  61. snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
  62. snowflake/cli/api/project/schemas/{identifier_model.py → v1/identifier_model.py} +0 -7
  63. snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
  64. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/native_app.py +4 -4
  65. snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
  66. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/callable.py +2 -2
  67. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/snowpark.py +2 -2
  68. snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
  69. snowflake/cli/api/project/schemas/{streamlit → v1/streamlit}/streamlit.py +2 -1
  70. snowflake/cli/api/rendering/sql_templates.py +6 -0
  71. snowflake/cli/api/rest_api.py +11 -5
  72. snowflake/cli/api/sql_execution.py +6 -15
  73. snowflake/cli/api/utils/definition_rendering.py +24 -4
  74. {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc4.dist-info}/METADATA +9 -7
  75. {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc4.dist-info}/RECORD +83 -79
  76. snowflake/cli/_plugins/nativeapp/init.py +0 -345
  77. snowflake/cli/api/entities/application_package_entity.py +0 -658
  78. snowflake/cli/api/project/schemas/entities/application_entity_model.py +0 -56
  79. snowflake/cli/api/project/schemas/entities/application_package_entity_model.py +0 -94
  80. snowflake/cli/api/project/schemas/streamlit/__init__.py +0 -13
  81. /snowflake/cli/{api/project/schemas/native_app → _plugins/helpers}/__init__.py +0 -0
  82. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/application.py +0 -0
  83. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/package.py +0 -0
  84. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/path_mapping.py +0 -0
  85. /snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/argument.py +0 -0
  86. {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc4.dist-info}/WHEEL +0 -0
  87. {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc4.dist-info}/entry_points.txt +0 -0
  88. {snowflake_cli_labs-3.0.0rc2.dist-info → snowflake_cli_labs-3.0.0rc4.dist-info}/licenses/LICENSE +0 -0
@@ -20,36 +20,62 @@ from snowflake.cli.api.entities.utils import render_script_template
20
20
  from snowflake.cli.api.project.schemas.entities.common import (
21
21
  SqlScriptHookType,
22
22
  )
23
- from snowflake.cli.api.project.schemas.native_app.application import (
24
- Application,
25
- ApplicationV11,
26
- )
27
- from snowflake.cli.api.project.schemas.native_app.native_app import NativeApp
28
- from snowflake.cli.api.project.schemas.native_app.package import Package, PackageV11
29
23
  from snowflake.cli.api.project.schemas.project_definition import (
30
24
  ProjectDefinition,
31
25
  ProjectDefinitionV2,
32
26
  )
33
- from snowflake.cli.api.project.schemas.snowpark.callable import (
27
+ from snowflake.cli.api.project.schemas.v1.native_app.application import (
28
+ Application,
29
+ ApplicationV11,
30
+ )
31
+ from snowflake.cli.api.project.schemas.v1.native_app.native_app import NativeApp
32
+ from snowflake.cli.api.project.schemas.v1.native_app.package import Package, PackageV11
33
+ from snowflake.cli.api.project.schemas.v1.snowpark.callable import (
34
34
  FunctionSchema,
35
35
  ProcedureSchema,
36
36
  )
37
- from snowflake.cli.api.project.schemas.snowpark.snowpark import Snowpark
38
- from snowflake.cli.api.project.schemas.streamlit.streamlit import Streamlit
37
+ from snowflake.cli.api.project.schemas.v1.snowpark.snowpark import Snowpark
38
+ from snowflake.cli.api.project.schemas.v1.streamlit.streamlit import Streamlit
39
39
  from snowflake.cli.api.rendering.jinja import get_basic_jinja_env
40
40
 
41
41
  log = logging.getLogger(__name__)
42
42
 
43
43
 
44
+ def _is_field_defined(template_context: Optional[Dict[str, Any]], *path: str) -> bool:
45
+ """
46
+ Determines if a field is defined in the provided template context. For example,
47
+
48
+ _is_field_defined({"ctx": {"native_app": {"bundle_root": "my_root"}}}, "ctx", "native_app", "bundle_root")
49
+
50
+ returns True. If the provided template context is None, this function returns True for all paths.
51
+
52
+ """
53
+ if template_context is None:
54
+ return True # No context, so assume that all variables are defined
55
+
56
+ current_dict = template_context
57
+ for key in path:
58
+ if not isinstance(current_dict, dict):
59
+ return False
60
+ if key not in current_dict:
61
+ return False
62
+ current_dict = current_dict[key]
63
+
64
+ return True
65
+
66
+
44
67
  def convert_project_definition_to_v2(
45
- project_root: Path, pd: ProjectDefinition, accept_templates: bool = False
68
+ project_root: Path,
69
+ pd: ProjectDefinition,
70
+ accept_templates: bool = False,
71
+ template_context: Optional[Dict[str, Any]] = None,
46
72
  ) -> ProjectDefinitionV2:
47
73
  _check_if_project_definition_meets_requirements(pd, accept_templates)
48
74
 
49
75
  snowpark_data = convert_snowpark_to_v2_data(pd.snowpark) if pd.snowpark else {}
50
76
  streamlit_data = convert_streamlit_to_v2_data(pd.streamlit) if pd.streamlit else {}
51
77
  native_app_data = (
52
- convert_native_app_to_v2_data(project_root, pd.native_app)
78
+ convert_native_app_to_v2_data(project_root, pd.native_app, template_context)
53
79
  if pd.native_app
54
80
  else {}
55
81
  )
@@ -157,6 +183,7 @@ def convert_streamlit_to_v2_data(streamlit: Streamlit) -> Dict[str, Any]:
157
183
  "type": "streamlit",
158
184
  "identifier": identifier,
159
185
  "title": streamlit.title,
186
+ "comment": streamlit.comment,
160
187
  "query_warehouse": streamlit.query_warehouse,
161
188
  "main_file": str(streamlit.main_file),
162
189
  "pages_dir": str(streamlit.pages_dir),
@@ -169,7 +196,9 @@ def convert_streamlit_to_v2_data(streamlit: Streamlit) -> Dict[str, Any]:
169
196
 
170
197
 
171
198
  def convert_native_app_to_v2_data(
172
- project_root, native_app: NativeApp
199
+ project_root,
200
+ native_app: NativeApp,
201
+ template_context: Optional[Dict[str, Any]] = None,
173
202
  ) -> Dict[str, Any]:
174
203
  def _make_meta(obj: Application | Package):
175
204
  meta = {}
@@ -249,14 +278,24 @@ def convert_native_app_to_v2_data(
249
278
  "identifier": package_identifier,
250
279
  "manifest": _find_manifest(),
251
280
  "artifacts": native_app.artifacts,
252
- "bundle_root": native_app.bundle_root,
253
- "generated_root": native_app.generated_root,
254
- "deploy_root": native_app.deploy_root,
255
- "stage": native_app.source_stage,
256
- "scratch_stage": native_app.scratch_stage,
257
281
  }
282
+
283
+ if _is_field_defined(template_context, "ctx", "native_app", "bundle_root"):
284
+ package["bundle_root"] = native_app.bundle_root
285
+ if _is_field_defined(template_context, "ctx", "native_app", "generated_root"):
286
+ package["generated_root"] = native_app.generated_root
287
+ if _is_field_defined(template_context, "ctx", "native_app", "deploy_root"):
288
+ package["deploy_root"] = native_app.deploy_root
289
+ if _is_field_defined(template_context, "ctx", "native_app", "source_stage"):
290
+ package["stage"] = native_app.source_stage
291
+ if _is_field_defined(template_context, "ctx", "native_app", "scratch_stage"):
292
+ package["scratch_stage"] = native_app.scratch_stage
293
+
258
294
  if native_app.package:
259
- package["distribution"] = native_app.package.distribution
295
+ if _is_field_defined(
296
+ template_context, "ctx", "native_app", "package", "distribution"
297
+ ):
298
+ package["distribution"] = native_app.package.distribution
260
299
  package_meta = _make_meta(native_app.package)
261
300
  if native_app.package.scripts:
262
301
  converted_post_deploy_hooks = _convert_package_script_files(
@@ -288,6 +327,10 @@ def convert_native_app_to_v2_data(
288
327
  if native_app.application:
289
328
  if app_meta := _make_meta(native_app.application):
290
329
  app["meta"] = app_meta
330
+ if _is_field_defined(
331
+ template_context, "ctx", "native_app", "application", "debug"
332
+ ):
333
+ app["debug"] = native_app.application.debug
291
334
 
292
335
  return {
293
336
  "entities": {
@@ -15,11 +15,10 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  from abc import ABC
18
- from typing import Generic, List, Optional, TypeVar, Union
18
+ from typing import Dict, Generic, List, Optional, TypeVar, Union
19
19
 
20
20
  from pydantic import Field, PrivateAttr, field_validator
21
21
  from snowflake.cli.api.identifiers import FQN
22
- from snowflake.cli.api.project.schemas.identifier_model import Identifier
23
22
  from snowflake.cli.api.project.schemas.updatable_model import (
24
23
  IdentifierField,
25
24
  UpdatableModel,
@@ -61,6 +60,12 @@ class MetaField(UpdatableModel):
61
60
  return mixins
62
61
 
63
62
 
63
+ class Identifier(UpdatableModel):
64
+ name: str = Field(title="Entity name")
65
+ schema_: Optional[str] = Field(title="Entity schema", alias="schema", default=None)
66
+ database: Optional[str] = Field(title="Entity database", default=None)
67
+
68
+
64
69
  class EntityModelBase(ABC, UpdatableModel):
65
70
  @classmethod
66
71
  def get_type(cls) -> str:
@@ -112,9 +117,17 @@ class TargetField(UpdatableModel, Generic[TargetType]):
112
117
  return self.__pydantic_generic_metadata__["args"][0]
113
118
 
114
119
 
115
- from typing import Dict, List, Optional
120
+ class ImportsBaseModel:
121
+ imports: Optional[List[str]] = Field(
122
+ title="Stage and path to previously uploaded files you want to import",
123
+ default=[],
124
+ )
116
125
 
117
- from pydantic import Field
126
+ def get_imports_sql(self) -> str | None:
127
+ if not self.imports:
128
+ return None
129
+ imports = ", ".join(f"'{i}'" for i in self.imports)
130
+ return f"IMPORTS = ({imports})"
118
131
 
119
132
 
120
133
  class ExternalAccessBaseModel:
@@ -16,23 +16,24 @@ from __future__ import annotations
16
16
 
17
17
  from typing import Dict, List, Union, get_args
18
18
 
19
- from snowflake.cli.api.entities.application_entity import ApplicationEntity
20
- from snowflake.cli.api.entities.application_package_entity import (
21
- ApplicationPackageEntity,
22
- )
23
- from snowflake.cli.api.entities.snowpark_entity import FunctionEntity, ProcedureEntity
24
- from snowflake.cli.api.entities.streamlit_entity import StreamlitEntity
25
- from snowflake.cli.api.project.schemas.entities.application_entity_model import (
19
+ from snowflake.cli._plugins.nativeapp.entities.application import (
20
+ ApplicationEntity,
26
21
  ApplicationEntityModel,
27
22
  )
28
- from snowflake.cli.api.project.schemas.entities.application_package_entity_model import (
23
+ from snowflake.cli._plugins.nativeapp.entities.application_package import (
24
+ ApplicationPackageEntity,
29
25
  ApplicationPackageEntityModel,
30
26
  )
31
- from snowflake.cli.api.project.schemas.entities.snowpark_entity import (
27
+ from snowflake.cli._plugins.snowpark.snowpark_entity import (
28
+ FunctionEntity,
29
+ ProcedureEntity,
30
+ )
31
+ from snowflake.cli._plugins.snowpark.snowpark_entity_model import (
32
32
  FunctionEntityModel,
33
33
  ProcedureEntityModel,
34
34
  )
35
- from snowflake.cli.api.project.schemas.entities.streamlit_entity_model import (
35
+ from snowflake.cli._plugins.streamlit.streamlit_entity import StreamlitEntity
36
+ from snowflake.cli._plugins.streamlit.streamlit_entity_model import (
36
37
  StreamlitEntityModel,
37
38
  )
38
39
 
@@ -19,10 +19,8 @@ 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
+ from snowflake.cli._plugins.nativeapp.entities.application import ApplicationEntityModel
22
23
  from snowflake.cli.api.project.errors import SchemaValidationError
23
- from snowflake.cli.api.project.schemas.entities.application_entity_model import (
24
- ApplicationEntityModel,
25
- )
26
24
  from snowflake.cli.api.project.schemas.entities.common import (
27
25
  TargetField,
28
26
  )
@@ -30,13 +28,13 @@ from snowflake.cli.api.project.schemas.entities.entities import (
30
28
  EntityModel,
31
29
  v2_entity_model_types_map,
32
30
  )
33
- from snowflake.cli.api.project.schemas.native_app.native_app import (
31
+ from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
32
+ from snowflake.cli.api.project.schemas.v1.native_app.native_app import (
34
33
  NativeApp,
35
34
  NativeAppV11,
36
35
  )
37
- from snowflake.cli.api.project.schemas.snowpark.snowpark import Snowpark
38
- from snowflake.cli.api.project.schemas.streamlit.streamlit import Streamlit
39
- from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
36
+ from snowflake.cli.api.project.schemas.v1.snowpark.snowpark import Snowpark
37
+ from snowflake.cli.api.project.schemas.v1.streamlit.streamlit import Streamlit
40
38
  from snowflake.cli.api.utils.types import Context
41
39
  from typing_extensions import Annotated
42
40
 
File without changes
@@ -19,16 +19,9 @@ from typing import Optional, cast
19
19
  from pydantic import Field
20
20
  from snowflake.cli.api.project.schemas.updatable_model import (
21
21
  IdentifierField,
22
- UpdatableModel,
23
22
  )
24
23
 
25
24
 
26
- class Identifier(UpdatableModel):
27
- name: str = Field(title="Entity name")
28
- schema_: Optional[str] = Field(title="Entity schema", alias="schema", default=None)
29
- database: Optional[str] = Field(title="Entity database", default=None)
30
-
31
-
32
25
  class ObjectIdentifierBaseModel:
33
26
  """
34
27
  Type representing a base class defining object that can be identified by fully qualified name (db.schema.name).
@@ -18,13 +18,13 @@ import re
18
18
  from typing import List, Optional, Union
19
19
 
20
20
  from pydantic import Field, field_validator
21
- from snowflake.cli.api.project.schemas.native_app.application import (
21
+ from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
22
+ from snowflake.cli.api.project.schemas.v1.native_app.application import (
22
23
  Application,
23
24
  ApplicationV11,
24
25
  )
25
- from snowflake.cli.api.project.schemas.native_app.package import Package, PackageV11
26
- from snowflake.cli.api.project.schemas.native_app.path_mapping import PathMapping
27
- from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
26
+ from snowflake.cli.api.project.schemas.v1.native_app.package import Package, PackageV11
27
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import PathMapping
28
28
  from snowflake.cli.api.project.util import (
29
29
  SCHEMA_AND_NAME,
30
30
  )
@@ -17,9 +17,9 @@ from __future__ import annotations
17
17
  from typing import Dict, List, Optional, Union
18
18
 
19
19
  from pydantic import Field, field_validator
20
- from snowflake.cli.api.project.schemas.identifier_model import ObjectIdentifierModel
21
- from snowflake.cli.api.project.schemas.snowpark.argument import Argument
22
20
  from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
21
+ from snowflake.cli.api.project.schemas.v1.identifier_model import ObjectIdentifierModel
22
+ from snowflake.cli.api.project.schemas.v1.snowpark.argument import Argument
23
23
 
24
24
 
25
25
  class _CallableBase(UpdatableModel):
@@ -17,11 +17,11 @@ from __future__ import annotations
17
17
  from typing import List, Optional
18
18
 
19
19
  from pydantic import Field
20
- from snowflake.cli.api.project.schemas.snowpark.callable import (
20
+ from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
21
+ from snowflake.cli.api.project.schemas.v1.snowpark.callable import (
21
22
  FunctionSchema,
22
23
  ProcedureSchema,
23
24
  )
24
- from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
25
25
 
26
26
 
27
27
  class Snowpark(UpdatableModel):
@@ -18,8 +18,8 @@ from pathlib import Path
18
18
  from typing import List, Optional
19
19
 
20
20
  from pydantic import Field
21
- from snowflake.cli.api.project.schemas.identifier_model import ObjectIdentifierModel
22
21
  from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
22
+ from snowflake.cli.api.project.schemas.v1.identifier_model import ObjectIdentifierModel
23
23
 
24
24
 
25
25
  class Streamlit(UpdatableModel, ObjectIdentifierModel(object_name="Streamlit")): # type: ignore
@@ -44,3 +44,4 @@ class Streamlit(UpdatableModel, ObjectIdentifierModel(object_name="Streamlit")):
44
44
  title: Optional[str] = Field(
45
45
  title="Human-readable title for the Streamlit dashboard", default=None
46
46
  )
47
+ comment: Optional[str] = Field(title="Comment for the Streamlit app", default=None)
@@ -21,6 +21,7 @@ from jinja2 import Environment, StrictUndefined, loaders, meta
21
21
  from snowflake.cli.api.cli_global_context import get_cli_context
22
22
  from snowflake.cli.api.console.console import cli_console
23
23
  from snowflake.cli.api.exceptions import InvalidTemplate
24
+ from snowflake.cli.api.metrics import CLICounterField
24
25
  from snowflake.cli.api.rendering.jinja import (
25
26
  CONTEXT_KEY,
26
27
  FUNCTION_KEY,
@@ -96,4 +97,9 @@ def snowflake_sql_jinja_render(content: str, data: Dict | None = None) -> str:
96
97
  context_data = get_cli_context().template_context
97
98
  context_data.update(data)
98
99
  env = choose_sql_jinja_env_based_on_template_syntax(content)
100
+
101
+ get_cli_context().metrics.set_counter(
102
+ CLICounterField.SQL_TEMPLATES, int(has_sql_templates(content))
103
+ )
104
+
99
105
  return env.from_string(content).render(context_data)
@@ -21,8 +21,9 @@ from typing import Any, Dict, Optional
21
21
  from click import ClickException
22
22
  from snowflake.cli.api.constants import SF_REST_API_URL_PREFIX
23
23
  from snowflake.connector.connection import SnowflakeConnection
24
- from snowflake.connector.errors import BadRequest, InterfaceError
24
+ from snowflake.connector.errors import BadRequest
25
25
  from snowflake.connector.network import SnowflakeRestful
26
+ from snowflake.connector.vendored.requests.exceptions import HTTPError
26
27
 
27
28
  log = logging.getLogger(__name__)
28
29
 
@@ -47,10 +48,10 @@ class RestApi:
47
48
  Check whether [get] endpoint exists under given URL.
48
49
  """
49
50
  try:
50
- result = self.send_rest_request(url, method="get")
51
- return bool(result) or result == []
52
- except InterfaceError as err:
53
- if "404 Not Found" in str(err):
51
+ self.send_rest_request(url, method="get")
52
+ return True
53
+ except HTTPError as err:
54
+ if err.response.status_code == 404:
54
55
  return False
55
56
  raise err
56
57
 
@@ -60,6 +61,10 @@ class RestApi:
60
61
  return bool(result)
61
62
  except BadRequest:
62
63
  return False
64
+ except HTTPError as err:
65
+ if err.response.status_code == 404:
66
+ return False
67
+ raise err
63
68
 
64
69
  def send_rest_request(
65
70
  self, url: str, method: str, data: Optional[Dict[str, Any]] = None
@@ -91,6 +96,7 @@ class RestApi:
91
96
  token=self.rest.token,
92
97
  data=json.dumps(data if data else {}),
93
98
  no_retry=True,
99
+ raise_raw_http_failure=True,
94
100
  )
95
101
 
96
102
  def _database_exists(self, db_name: str) -> bool:
@@ -98,11 +98,7 @@ class SqlExecutor:
98
98
  )
99
99
 
100
100
  def current_role(self) -> str:
101
- *_, cursor = self._execute_string(
102
- "select current_role()", cursor_class=DictCursor
103
- )
104
- role_result = cursor.fetchone()
105
- return role_result["CURRENT_ROLE()"]
101
+ return self._execute_query(f"select current_role()").fetchone()[0]
106
102
 
107
103
  @contextmanager
108
104
  def use_role(self, new_role: str):
@@ -110,10 +106,7 @@ class SqlExecutor:
110
106
  Switches to a different role for a while, then switches back.
111
107
  This is a no-op if the requested role is already active.
112
108
  """
113
- role_result = self._execute_query(
114
- f"select current_role()", cursor_class=DictCursor
115
- ).fetchone()
116
- prev_role = role_result["CURRENT_ROLE()"]
109
+ prev_role = self.current_role()
117
110
  is_different_role = new_role.lower() != prev_role.lower()
118
111
  if is_different_role:
119
112
  self._log.debug("Assuming different role: %s", new_role)
@@ -126,9 +119,9 @@ class SqlExecutor:
126
119
 
127
120
  def session_has_warehouse(self) -> bool:
128
121
  result = self._execute_query(
129
- "select current_warehouse() is not null as result", cursor_class=DictCursor
122
+ "select current_warehouse() is not null"
130
123
  ).fetchone()
131
- return bool(result.get("RESULT"))
124
+ return bool(result[0])
132
125
 
133
126
  @contextmanager
134
127
  def use_warehouse(self, new_wh: str):
@@ -138,12 +131,10 @@ class SqlExecutor:
138
131
  If there is no default warehouse in the account, it will throw an error.
139
132
  """
140
133
 
141
- wh_result = self._execute_query(
142
- f"select current_warehouse()", cursor_class=DictCursor
143
- ).fetchone()
134
+ wh_result = self._execute_query(f"select current_warehouse()").fetchone()
144
135
  # If user has an assigned default warehouse, prev_wh will contain a value even if the warehouse is suspended.
145
136
  try:
146
- prev_wh = wh_result["CURRENT_WAREHOUSE()"]
137
+ prev_wh = wh_result[0]
147
138
  except:
148
139
  prev_wh = None
149
140
 
@@ -19,8 +19,10 @@ from typing import Any, Optional
19
19
 
20
20
  from jinja2 import Environment, TemplateSyntaxError, nodes
21
21
  from packaging.version import Version
22
+ from snowflake.cli.api.cli_global_context import get_cli_context
22
23
  from snowflake.cli.api.console import cli_console as cc
23
24
  from snowflake.cli.api.exceptions import CycleDetectedError, InvalidTemplate
25
+ from snowflake.cli.api.metrics import CLICounterField
24
26
  from snowflake.cli.api.project.schemas.project_definition import (
25
27
  ProjectProperties,
26
28
  build_project_definition,
@@ -266,6 +268,12 @@ def _get_referenced_vars_in_definition(
266
268
  return referenced_vars
267
269
 
268
270
 
271
+ def _has_referenced_vars_in_definition(
272
+ template_env: TemplatedEnvironment, definition: Definition
273
+ ) -> bool:
274
+ return len(_get_referenced_vars_in_definition(template_env, definition)) > 0
275
+
276
+
269
277
  def _template_version_warning():
270
278
  cc.warning(
271
279
  "Ignoring template pattern in project definition file. "
@@ -291,6 +299,17 @@ def _add_defaults_to_definition(original_definition: Definition) -> Definition:
291
299
  return definition_with_defaults
292
300
 
293
301
 
302
+ def _update_metrics(template_env: TemplatedEnvironment, definition: Definition):
303
+ metrics = get_cli_context().metrics
304
+
305
+ # render_definition_template is invoked multiple times both by the user
306
+ # and by us so we should make sure we don't overwrite a 1 with a 0 here
307
+ metrics.set_counter_default(CLICounterField.PDF_TEMPLATES, 0)
308
+
309
+ if _has_referenced_vars_in_definition(template_env, definition):
310
+ metrics.set_counter(CLICounterField.PDF_TEMPLATES, 1)
311
+
312
+
294
313
  def render_definition_template(
295
314
  original_definition: Optional[Definition], context_overrides: Context
296
315
  ) -> ProjectProperties:
@@ -326,10 +345,7 @@ def render_definition_template(
326
345
  definition["definition_version"]
327
346
  ) < Version("1.1"):
328
347
  try:
329
- referenced_vars = _get_referenced_vars_in_definition(
330
- template_env, definition
331
- )
332
- if referenced_vars:
348
+ if _has_referenced_vars_in_definition(template_env, definition):
333
349
  _template_version_warning()
334
350
  except Exception:
335
351
  # also warn on Exception, as it means the user is incorrectly attempting to use templating
@@ -340,6 +356,10 @@ def render_definition_template(
340
356
  project_context[CONTEXT_KEY]["env"] = environment_overrides
341
357
  return ProjectProperties(project_definition, project_context)
342
358
 
359
+ # need to have the metrics added here since we add defaults to the
360
+ # definition that the user might not have added themselves later
361
+ _update_metrics(template_env, definition)
362
+
343
363
  definition = _add_defaults_to_definition(definition)
344
364
  project_context = {CONTEXT_KEY: definition}
345
365
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: snowflake-cli-labs
3
- Version: 3.0.0rc2
3
+ Version: 3.0.0rc4
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
@@ -222,14 +222,14 @@ Requires-Dist: jinja2==3.1.4
222
222
  Requires-Dist: packaging
223
223
  Requires-Dist: pip
224
224
  Requires-Dist: pluggy==1.5.0
225
- Requires-Dist: pydantic==2.9.1
225
+ Requires-Dist: pydantic==2.9.2
226
226
  Requires-Dist: pyyaml==6.0.2
227
227
  Requires-Dist: requests==2.32.3
228
228
  Requires-Dist: requirements-parser==0.11.0
229
- Requires-Dist: rich==13.8.0
230
- Requires-Dist: setuptools==74.1.2
231
- Requires-Dist: snowflake-connector-python[secure-local-storage]==3.12.1
232
- Requires-Dist: snowflake-core==0.8.0; python_version < '3.12'
229
+ Requires-Dist: rich==13.8.1
230
+ Requires-Dist: setuptools==75.1.0
231
+ Requires-Dist: snowflake-connector-python[secure-local-storage]==3.12.2
232
+ Requires-Dist: snowflake-core==0.12.1; python_version < '3.12'
233
233
  Requires-Dist: snowflake-snowpark-python>=1.15.0; python_version < '3.12'
234
234
  Requires-Dist: tomlkit==0.13.2
235
235
  Requires-Dist: typer==0.12.5
@@ -238,8 +238,10 @@ Provides-Extra: development
238
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.2; extra == 'development'
241
+ Requires-Dist: pytest==8.3.3; extra == 'development'
242
242
  Requires-Dist: syrupy==4.7.1; extra == 'development'
243
+ Provides-Extra: packaging
244
+ Requires-Dist: pyinstaller~=6.10; extra == 'packaging'
243
245
  Description-Content-Type: text/markdown
244
246
 
245
247
  <!--