snowflake-cli-labs 3.0.0rc3__py3-none-any.whl → 3.0.0rc5__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 (44) hide show
  1. snowflake/cli/__about__.py +1 -1
  2. snowflake/cli/_app/telemetry.py +28 -0
  3. snowflake/cli/_plugins/connection/commands.py +9 -4
  4. snowflake/cli/_plugins/helpers/commands.py +34 -1
  5. snowflake/cli/_plugins/nativeapp/codegen/compiler.py +5 -0
  6. snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +4 -0
  7. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +3 -0
  8. snowflake/cli/_plugins/nativeapp/commands.py +9 -86
  9. snowflake/cli/_plugins/nativeapp/entities/__init__.py +0 -0
  10. snowflake/cli/_plugins/nativeapp/{application_entity.py → entities/application.py} +266 -39
  11. snowflake/cli/_plugins/nativeapp/{application_package_entity.py → entities/application_package.py} +357 -72
  12. snowflake/cli/_plugins/nativeapp/manager.py +62 -183
  13. snowflake/cli/_plugins/nativeapp/run_processor.py +6 -6
  14. snowflake/cli/_plugins/nativeapp/teardown_processor.py +2 -4
  15. snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +2 -4
  16. snowflake/cli/_plugins/nativeapp/version/commands.py +1 -15
  17. snowflake/cli/_plugins/nativeapp/version/version_processor.py +16 -82
  18. snowflake/cli/_plugins/object/manager.py +36 -15
  19. snowflake/cli/_plugins/streamlit/commands.py +12 -0
  20. snowflake/cli/_plugins/streamlit/manager.py +4 -0
  21. snowflake/cli/_plugins/workspace/commands.py +33 -0
  22. snowflake/cli/api/cli_global_context.py +7 -0
  23. snowflake/cli/api/commands/decorators.py +14 -0
  24. snowflake/cli/api/commands/flags.py +18 -0
  25. snowflake/cli/api/config.py +25 -6
  26. snowflake/cli/api/connections.py +3 -1
  27. snowflake/cli/api/entities/common.py +1 -0
  28. snowflake/cli/api/entities/utils.py +3 -0
  29. snowflake/cli/api/metrics.py +92 -0
  30. snowflake/cli/api/project/definition_conversion.py +69 -22
  31. snowflake/cli/api/project/definition_manager.py +5 -5
  32. snowflake/cli/api/project/schemas/entities/entities.py +3 -5
  33. snowflake/cli/api/project/schemas/project_definition.py +1 -3
  34. snowflake/cli/api/rendering/sql_templates.py +6 -0
  35. snowflake/cli/api/rest_api.py +11 -5
  36. snowflake/cli/api/utils/definition_rendering.py +24 -4
  37. {snowflake_cli_labs-3.0.0rc3.dist-info → snowflake_cli_labs-3.0.0rc5.dist-info}/METADATA +4 -2
  38. {snowflake_cli_labs-3.0.0rc3.dist-info → snowflake_cli_labs-3.0.0rc5.dist-info}/RECORD +41 -42
  39. snowflake/cli/_plugins/nativeapp/application_entity_model.py +0 -56
  40. snowflake/cli/_plugins/nativeapp/application_package_entity_model.py +0 -94
  41. snowflake/cli/_plugins/nativeapp/init.py +0 -345
  42. {snowflake_cli_labs-3.0.0rc3.dist-info → snowflake_cli_labs-3.0.0rc5.dist-info}/WHEEL +0 -0
  43. {snowflake_cli_labs-3.0.0rc3.dist-info → snowflake_cli_labs-3.0.0rc5.dist-info}/entry_points.txt +0 -0
  44. {snowflake_cli_labs-3.0.0rc3.dist-info → snowflake_cli_labs-3.0.0rc5.dist-info}/licenses/LICENSE +0 -0
@@ -14,4 +14,4 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- VERSION = "3.0.0rc3"
17
+ VERSION = "3.0.0rc5"
@@ -37,6 +37,12 @@ from snowflake.connector.telemetry import (
37
37
  from snowflake.connector.time_util import get_time_millis
38
38
 
39
39
 
40
+ @unique
41
+ class CLIInstallationSource(Enum):
42
+ BINARY = "binary"
43
+ PYPI = "pypi"
44
+
45
+
40
46
  @unique
41
47
  class CLITelemetryField(Enum):
42
48
  # Basic information
@@ -44,6 +50,7 @@ class CLITelemetryField(Enum):
44
50
  VERSION_CLI = "version_cli"
45
51
  VERSION_PYTHON = "version_python"
46
52
  VERSION_OS = "version_os"
53
+ INSTALLATION_SOURCE = "installation_source"
47
54
  # Command execution context
48
55
  COMMAND = "command"
49
56
  COMMAND_GROUP = "command_group"
@@ -54,6 +61,8 @@ class CLITelemetryField(Enum):
54
61
  COMMAND_EXECUTION_TIME = "command_execution_time"
55
62
  # Configuration
56
63
  CONFIG_FEATURE_FLAGS = "config_feature_flags"
64
+ # Metrics
65
+ COUNTERS = "counters"
57
66
  # Information
58
67
  EVENT = "event"
59
68
  ERROR_MSG = "error_msg"
@@ -72,6 +81,16 @@ class TelemetryEvent(Enum):
72
81
  TelemetryDict = Dict[Union[CLITelemetryField, TelemetryField], Any]
73
82
 
74
83
 
84
+ def _get_command_metrics() -> TelemetryDict:
85
+ cli_context = get_cli_context()
86
+
87
+ return {
88
+ CLITelemetryField.COUNTERS: {
89
+ **cli_context.metrics.counters,
90
+ }
91
+ }
92
+
93
+
75
94
  def _find_command_info() -> TelemetryDict:
76
95
  ctx = click.get_current_context()
77
96
  command_path = ctx.command_path.split(" ")[1:]
@@ -97,6 +116,12 @@ def _get_definition_version() -> str | None:
97
116
  return None
98
117
 
99
118
 
119
+ def _get_installation_source() -> CLIInstallationSource:
120
+ if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
121
+ return CLIInstallationSource.BINARY
122
+ return CLIInstallationSource.PYPI
123
+
124
+
100
125
  def command_info() -> str:
101
126
  info = _find_command_info()
102
127
  command = ".".join(info[CLITelemetryField.COMMAND])
@@ -119,6 +144,7 @@ class CLITelemetryClient:
119
144
  ) -> Dict[str, Any]:
120
145
  data = {
121
146
  CLITelemetryField.SOURCE: PARAM_APPLICATION_NAME,
147
+ CLITelemetryField.INSTALLATION_SOURCE: _get_installation_source().value,
122
148
  CLITelemetryField.VERSION_CLI: VERSION,
123
149
  CLITelemetryField.VERSION_OS: platform.platform(),
124
150
  CLITelemetryField.VERSION_PYTHON: python_version(),
@@ -168,6 +194,7 @@ def log_command_result(execution: ExecutionMetadata):
168
194
  CLITelemetryField.COMMAND_EXECUTION_ID: execution.execution_id,
169
195
  CLITelemetryField.COMMAND_RESULT_STATUS: execution.status.value,
170
196
  CLITelemetryField.COMMAND_EXECUTION_TIME: execution.get_duration(),
197
+ **_get_command_metrics(),
171
198
  }
172
199
  )
173
200
 
@@ -183,6 +210,7 @@ def log_command_execution_error(exception: Exception, execution: ExecutionMetada
183
210
  CLITelemetryField.ERROR_TYPE: exception_type,
184
211
  CLITelemetryField.IS_CLI_EXCEPTION: is_cli_exception,
185
212
  CLITelemetryField.COMMAND_EXECUTION_TIME: execution.get_duration(),
213
+ **_get_command_metrics(),
186
214
  }
187
215
  )
188
216
 
@@ -33,7 +33,7 @@ from snowflake.cli.api.commands.flags import (
33
33
  from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
34
34
  from snowflake.cli.api.config import (
35
35
  ConnectionConfig,
36
- add_connection,
36
+ add_connection_to_proper_file,
37
37
  connection_exists,
38
38
  get_all_connections,
39
39
  get_connection_dict,
@@ -49,7 +49,7 @@ from snowflake.cli.api.output.types import (
49
49
  ObjectResult,
50
50
  )
51
51
  from snowflake.connector import ProgrammingError
52
- from snowflake.connector.config_manager import CONFIG_MANAGER
52
+ from snowflake.connector.constants import CONNECTIONS_FILE
53
53
 
54
54
  app = SnowTyperFactory(
55
55
  name="connection",
@@ -91,6 +91,11 @@ def list_connections(**options) -> CommandResult:
91
91
  }
92
92
  for connection_name, connection_config in connections.items()
93
93
  )
94
+
95
+ if CONNECTIONS_FILE.exists():
96
+ cli_console.warning(
97
+ f"Reading connections from {CONNECTIONS_FILE}. Entries from config.toml are ignored."
98
+ )
94
99
  return CollectionResult(result)
95
100
 
96
101
 
@@ -255,7 +260,7 @@ def add(
255
260
  if connection_exists(connection_name):
256
261
  raise ClickException(f"Connection {connection_name} already exists")
257
262
 
258
- add_connection(
263
+ connections_file = add_connection_to_proper_file(
259
264
  connection_name,
260
265
  ConnectionConfig(
261
266
  account=account,
@@ -279,7 +284,7 @@ def add(
279
284
  )
280
285
 
281
286
  return MessageResult(
282
- f"Wrote new connection {connection_name} to {CONFIG_MANAGER.file_path}"
287
+ f"Wrote new connection {connection_name} to {connections_file}"
283
288
  )
284
289
 
285
290
 
@@ -16,6 +16,7 @@ from __future__ import annotations
16
16
 
17
17
  import typer
18
18
  import yaml
19
+ from click import ClickException
19
20
  from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
20
21
  from snowflake.cli.api.output.types import MessageResult
21
22
  from snowflake.cli.api.project.definition_conversion import (
@@ -35,23 +36,55 @@ def v1_to_v2(
35
36
  accept_templates: bool = typer.Option(
36
37
  False, "-t", "--accept-templates", help="Allows the migration of templates."
37
38
  ),
39
+ migrate_local_yml: (bool | None) = typer.Option(
40
+ None,
41
+ "-l",
42
+ "--migrate-local-overrides/--no-migrate-local-overrides",
43
+ help=(
44
+ "Merge values in snowflake.local.yml into the main project definition. "
45
+ "The snowflake.local.yml file will not be migrated, "
46
+ "instead its values will be reflected in the output snowflake.yml file. "
47
+ "If unset and snowflake.local.yml is present, an error will be raised."
48
+ ),
49
+ show_default=False,
50
+ ),
38
51
  **options,
39
52
  ):
40
53
  """Migrates the Snowpark, Streamlit, and Native App project definition files from V1 to V2."""
41
54
  manager = DefinitionManager()
55
+ local_yml_path = manager.project_root / "snowflake.local.yml"
56
+ has_local_yml = local_yml_path in manager.project_config_paths
57
+ if has_local_yml:
58
+ if migrate_local_yml is None:
59
+ raise ClickException(
60
+ "snowflake.local.yml file detected, "
61
+ "please specify --migrate-local-overrides to include "
62
+ "or --no-migrate-local-overrides to exclude its values."
63
+ )
64
+ if not migrate_local_yml:
65
+ # If we don't want the local file,
66
+ # remove it from the list of paths to load
67
+ manager.project_config_paths.remove(local_yml_path)
68
+
42
69
  pd = manager.unrendered_project_definition
43
70
 
44
71
  if pd.meets_version_requirement("2"):
45
72
  return MessageResult("Project definition is already at version 2.")
46
73
 
47
- pd_v2 = convert_project_definition_to_v2(manager.project_root, pd, accept_templates)
74
+ pd_v2 = convert_project_definition_to_v2(
75
+ manager.project_root, pd, accept_templates, manager.template_context
76
+ )
48
77
 
49
78
  SecurePath("snowflake.yml").rename("snowflake_V1.yml")
79
+ if has_local_yml:
80
+ SecurePath("snowflake.local.yml").rename("snowflake_V1.local.yml")
50
81
  with open("snowflake.yml", "w") as file:
51
82
  yaml.dump(
52
83
  pd_v2.model_dump(
53
84
  exclude_unset=True, exclude_none=True, mode="json", by_alias=True
54
85
  ),
55
86
  file,
87
+ sort_keys=False,
88
+ width=float("inf"), # Don't break lines
56
89
  )
57
90
  return MessageResult("Project definition migrated to version 2.")
@@ -34,7 +34,9 @@ from snowflake.cli._plugins.nativeapp.codegen.templates.templates_processor impo
34
34
  TemplatesProcessor,
35
35
  )
36
36
  from snowflake.cli._plugins.nativeapp.feature_flags import FeatureFlag
37
+ from snowflake.cli.api.cli_global_context import get_cli_context
37
38
  from snowflake.cli.api.console import cli_console as cc
39
+ from snowflake.cli.api.metrics import CLICounterField
38
40
  from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import (
39
41
  ProcessorMapping,
40
42
  )
@@ -72,6 +74,9 @@ class NativeAppCompiler:
72
74
  Go through every artifact object in the project definition of a native app, and execute processors in order of specification for each of the artifact object.
73
75
  May have side-effects on the filesystem by either directly editing source files or the deploy root.
74
76
  """
77
+ metrics = get_cli_context().metrics
78
+ metrics.set_counter_default(CLICounterField.TEMPLATES_PROCESSOR, 0)
79
+ metrics.set_counter_default(CLICounterField.SNOWPARK_PROCESSOR, 0)
75
80
 
76
81
  if not self._should_invoke_processors():
77
82
  return
@@ -48,7 +48,9 @@ from snowflake.cli._plugins.nativeapp.codegen.snowpark.models import (
48
48
  NativeAppExtensionFunction,
49
49
  )
50
50
  from snowflake.cli._plugins.stage.diff import to_stage_path
51
+ from snowflake.cli.api.cli_global_context import get_cli_context
51
52
  from snowflake.cli.api.console import cli_console as cc
53
+ from snowflake.cli.api.metrics import CLICounterField
52
54
  from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import (
53
55
  PathMapping,
54
56
  ProcessorMapping,
@@ -176,6 +178,8 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
176
178
  setup script with generated SQL that registers these functions.
177
179
  """
178
180
 
181
+ get_cli_context().metrics.set_counter(CLICounterField.SNOWPARK_PROCESSOR, 1)
182
+
179
183
  bundle_map = BundleMap(
180
184
  project_root=self._bundle_ctx.project_root,
181
185
  deploy_root=self._bundle_ctx.deploy_root,
@@ -25,6 +25,7 @@ from snowflake.cli._plugins.nativeapp.codegen.artifact_processor import (
25
25
  from snowflake.cli._plugins.nativeapp.exceptions import InvalidTemplateInFileError
26
26
  from snowflake.cli.api.cli_global_context import get_cli_context
27
27
  from snowflake.cli.api.console import cli_console as cc
28
+ from snowflake.cli.api.metrics import CLICounterField
28
29
  from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import (
29
30
  PathMapping,
30
31
  ProcessorMapping,
@@ -98,6 +99,8 @@ class TemplatesProcessor(ArtifactProcessor):
98
99
  Process the artifact by executing the template expansion logic on it.
99
100
  """
100
101
 
102
+ get_cli_context().metrics.set_counter(CLICounterField.TEMPLATES_PROCESSOR, 1)
103
+
101
104
  bundle_map = BundleMap(
102
105
  project_root=self._bundle_ctx.project_root,
103
106
  deploy_root=self._bundle_ctx.deploy_root,
@@ -22,20 +22,15 @@ from textwrap import dedent
22
22
  from typing import Generator, Iterable, List, Optional, cast
23
23
 
24
24
  import typer
25
- from snowflake.cli._plugins.nativeapp.application_entity_model import (
26
- ApplicationEntityModel,
27
- )
28
- from snowflake.cli._plugins.nativeapp.application_package_entity_model import (
29
- ApplicationPackageEntityModel,
30
- )
25
+ from click.exceptions import ClickException
31
26
  from snowflake.cli._plugins.nativeapp.common_flags import (
32
27
  ForceOption,
33
28
  InteractiveOption,
34
29
  ValidateOption,
35
30
  )
36
- from snowflake.cli._plugins.nativeapp.init import (
37
- OFFICIAL_TEMPLATES_GITHUB_URL,
38
- nativeapp_init,
31
+ from snowflake.cli._plugins.nativeapp.entities.application import ApplicationEntityModel
32
+ from snowflake.cli._plugins.nativeapp.entities.application_package import (
33
+ ApplicationPackageEntityModel,
39
34
  )
40
35
  from snowflake.cli._plugins.nativeapp.manager import NativeAppManager
41
36
  from snowflake.cli._plugins.nativeapp.policy import (
@@ -47,10 +42,6 @@ from snowflake.cli._plugins.nativeapp.run_processor import NativeAppRunProcessor
47
42
  from snowflake.cli._plugins.nativeapp.teardown_processor import (
48
43
  NativeAppTeardownProcessor,
49
44
  )
50
- from snowflake.cli._plugins.nativeapp.utils import (
51
- get_first_paragraph_from_markdown_file,
52
- shallow_git_clone,
53
- )
54
45
  from snowflake.cli._plugins.nativeapp.v2_conversions.v2_to_v1_decorator import (
55
46
  find_entity,
56
47
  nativeapp_definition_v2_to_v1,
@@ -71,7 +62,6 @@ from snowflake.cli.api.entities.common import EntityActions
71
62
  from snowflake.cli.api.exceptions import IncompatibleParametersError
72
63
  from snowflake.cli.api.output.formats import OutputFormat
73
64
  from snowflake.cli.api.output.types import (
74
- CollectionResult,
75
65
  CommandResult,
76
66
  MessageResult,
77
67
  ObjectResult,
@@ -79,7 +69,6 @@ from snowflake.cli.api.output.types import (
79
69
  )
80
70
  from snowflake.cli.api.project.project_verification import assert_project_type
81
71
  from snowflake.cli.api.project.schemas.project_definition import ProjectDefinitionV1
82
- from snowflake.cli.api.secure_path import SecurePath
83
72
  from typing_extensions import Annotated
84
73
 
85
74
  app = SnowTyperFactory(
@@ -91,81 +80,15 @@ app.add_typer(versions_app)
91
80
  log = logging.getLogger(__name__)
92
81
 
93
82
 
94
- @app.command("init")
95
- def app_init(
96
- path: str = typer.Argument(
97
- ...,
98
- help=f"""Directory to be initialized with the Snowflake Native App project. This directory must not already exist.""",
99
- show_default=False,
100
- ),
101
- name: str = typer.Option(
102
- None,
103
- help=f"""The name of the Snowflake Native App project to include in snowflake.yml. When not specified, it is
104
- generated from the name of the directory. Names are assumed to be unquoted identifiers whenever possible, but
105
- can be forced to be quoted by including the surrounding quote characters in the provided value.""",
106
- ),
107
- template_repo: str = typer.Option(
108
- None,
109
- help=f"""Specifies the git URL to a template repository, which can be a template itself or contain many templates inside it,
110
- such as https://github.com/snowflakedb/native-apps-templates.git for all official Snowflake Native App with Snowflake CLI templates.
111
- If using a private Github repo, you might be prompted to enter your Github username and password.
112
- Please use your personal access token in the password prompt, and refer to
113
- https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.""",
114
- ),
115
- template: str = typer.Option(
116
- None,
117
- help="A specific template name within the template repo to use as template for the Snowflake Native App project. Example: Default is basic if `--template-repo` is https://github.com/snowflakedb/native-apps-templates.git, and None if any other --template-repo is specified.",
118
- ),
119
- **options,
120
- ) -> CommandResult:
121
- """
122
- Initializes a Snowflake Native App project.
83
+ @app.command("init", hidden=True)
84
+ def app_init(**options):
123
85
  """
124
- project = nativeapp_init(
125
- path=path, name=name, git_url=template_repo, template=template
126
- )
127
- return MessageResult(
128
- f"Snowflake Native App project {project.name} has been created at: {path}"
129
- )
130
-
86
+ *** Deprecated. Use snow init instead ***
131
87
 
132
- @app.command("list-templates", hidden=True)
133
- def app_list_templates(**options) -> CommandResult:
134
- """
135
- Prints information regarding the official templates that can be used with snow app init.
88
+ Initializes a Snowflake Native App project.
136
89
  """
137
- with SecurePath.temporary_directory() as temp_path:
138
- from git import rmtree as git_rmtree
139
-
140
- repo = shallow_git_clone(OFFICIAL_TEMPLATES_GITHUB_URL, temp_path.path)
141
-
142
- # Mark a directory as a template if a project definition jinja template is inside
143
- template_directories = [
144
- entry.name
145
- for entry in repo.head.commit.tree
146
- if (temp_path / entry.name / "snowflake.yml.jinja").exists()
147
- ]
148
-
149
- # get the template descriptions from the README.md in its directory
150
- template_descriptions = [
151
- get_first_paragraph_from_markdown_file(
152
- (temp_path / directory / "README.md").path
153
- )
154
- for directory in template_directories
155
- ]
156
-
157
- result = (
158
- {"template": directory, "description": description}
159
- for directory, description in zip(
160
- template_directories, template_descriptions
161
- )
162
- )
163
-
164
- # proactively clean up here to avoid permission issues on Windows
165
- repo.close()
166
- git_rmtree(temp_path.path)
167
90
 
168
- return CollectionResult(result)
91
+ raise ClickException("This command has been removed. Use `snow init` instead.")
169
92
 
170
93
 
171
94
  @app.command("bundle")
File without changes