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
@@ -1,345 +0,0 @@
1
- # Copyright (c) 2024 Snowflake Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- from __future__ import annotations
16
-
17
- import logging
18
- import re
19
- from pathlib import Path
20
- from typing import Optional
21
-
22
- from click.exceptions import ClickException
23
- from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB
24
- from snowflake.cli.api.exceptions import MissingConfiguration
25
- from snowflake.cli.api.project.definition_manager import DefinitionManager
26
- from snowflake.cli.api.project.util import (
27
- is_valid_identifier,
28
- is_valid_unquoted_identifier,
29
- to_identifier,
30
- )
31
- from snowflake.cli.api.rendering.jinja import jinja_render_from_file
32
- from snowflake.cli.api.secure_path import SecurePath
33
- from yaml import dump, safe_dump, safe_load
34
-
35
- log = logging.getLogger(__name__)
36
-
37
- OFFICIAL_TEMPLATES_GITHUB_URL = "https://github.com/snowflakedb/native-apps-templates"
38
- BASIC_TEMPLATE = "basic"
39
-
40
-
41
- class InitError(ClickException):
42
- """
43
- Snowflake Native App project could not be initiated due to an underlying error.
44
- """
45
-
46
- def __init__(self):
47
- super().__init__(self.__doc__)
48
-
49
-
50
- class ProjectNameInvalidError(ClickException):
51
- """
52
- Intended project name does not qualify as a valid identifier.
53
- """
54
-
55
- def __init__(self, project_name: str):
56
- super().__init__(
57
- f"Intended project name does not qualify as a valid identifier: {project_name}"
58
- )
59
-
60
-
61
- class RenderingFromJinjaError(ClickException):
62
- """
63
- Could not complete rendering file from Jinja template.
64
- """
65
-
66
- def __init__(self, name: str):
67
- super().__init__(
68
- f"Could not complete rendering file from Jinja template: {name}"
69
- )
70
-
71
-
72
- class CannotInitializeAnExistingProjectError(ClickException):
73
- """
74
- Cannot initialize a new project within an existing Snowflake Native App project.
75
- """
76
-
77
- def __init__(self):
78
- super().__init__(self.__doc__)
79
-
80
-
81
- class DirectoryAlreadyExistsError(ClickException):
82
- """
83
- Directory already contains a project with the intended name.
84
- """
85
-
86
- name: str
87
-
88
- def __init__(self, name: str):
89
- super().__init__(
90
- f"The directory {name} already exists. Please specify a different path for the project."
91
- )
92
- self.name = name
93
-
94
-
95
- class TemplateNotFoundError(ClickException):
96
- """
97
- Specified template was not found.
98
- """
99
-
100
- def __init__(self, template_name):
101
- super().__init__(f"Specified template was not found: {template_name}")
102
-
103
-
104
- class ProjectDescriptor:
105
- """
106
- Encapsulates static properties of a Snowflake Native App project.
107
- """
108
-
109
- def __init__(self, *, name, path):
110
- self.name = name
111
- self.path = path
112
-
113
-
114
- def _to_yaml_string(identifier: str):
115
- """
116
- Returns the YAML representation of an identifier, suitable for including in a YAML jinja template
117
- """
118
- if is_valid_unquoted_identifier(identifier):
119
- return identifier
120
- else:
121
- return dump(identifier).rstrip()
122
-
123
-
124
- def _render_snowflake_yml(parent_to_snowflake_yml: Path, project_identifier: str):
125
- """
126
- Create a snowflake.yml file from a jinja template at a given path.
127
-
128
- Args:
129
- parent_to_snowflake_yml (Path): The parent directory of snowflake.yml.jinja, and later snowflake.yml
130
- project_identifier (str): The name of the project to be created, as a Snowflake identifier.
131
-
132
- Returns:
133
- None
134
- """
135
-
136
- snowflake_yml_jinja = "snowflake.yml.jinja"
137
-
138
- try:
139
- jinja_render_from_file(
140
- template_path=parent_to_snowflake_yml / snowflake_yml_jinja,
141
- data={
142
- # generic_render_template operates on text, not YAML, so escape before rendering
143
- "project_name": _to_yaml_string(project_identifier)
144
- },
145
- output_file_path=parent_to_snowflake_yml / "snowflake.yml",
146
- )
147
- (parent_to_snowflake_yml / snowflake_yml_jinja).unlink()
148
- except Exception as err:
149
- log.error(err)
150
- raise RenderingFromJinjaError(snowflake_yml_jinja)
151
-
152
-
153
- def _replace_snowflake_yml_name_with_project(
154
- target_directory: Path, project_identifier: str
155
- ):
156
- """
157
- Replace the native_app schema's "name" field in a snowflake.yml file with its parent directory name, i.e. the Snowflake Native App project, as the default start.
158
- This does not change the name in any other snowflake.*.yml as snowflake.yml is the base file and all others are overrides for the user to customize.
159
-
160
- Args:
161
- target_directory (str): The directory containing snowflake.yml at its root.
162
- project_identifier (str): The name of the project to be created, as a Snowflake identifier.
163
-
164
- Returns:
165
- None
166
- """
167
-
168
- path_to_snowflake_yml = SecurePath(target_directory) / "snowflake.yml"
169
- contents = None
170
-
171
- with path_to_snowflake_yml.open(
172
- "r", read_file_limit_mb=DEFAULT_SIZE_LIMIT_MB
173
- ) as file:
174
- contents = safe_load(file)
175
-
176
- if (
177
- (contents is not None)
178
- and ("native_app" in contents)
179
- and ("name" in contents["native_app"])
180
- and (contents["native_app"]["name"] != project_identifier)
181
- ):
182
- contents["native_app"]["name"] = project_identifier
183
- with path_to_snowflake_yml.open("w") as file:
184
- safe_dump(contents, file, sort_keys=False)
185
-
186
-
187
- def _validate_and_update_snowflake_yml(target_directory: Path, project_identifier: str):
188
- """
189
- Update the native_app name key in the snowflake.yml file and perform validation on the entire file.
190
- This step is useful when cloning from a non-Snowflake template repo which may directly have a snowflake.yml file.
191
-
192
- Args:
193
- target_directory (Path): The directory containing snowflake.yml at its root.
194
- project_identifier (str): The name of the project to be created, as a Snowflake identifier.
195
-
196
- Returns:
197
- None
198
- """
199
- # 1. Determine if a snowflake.yml file exists, at the very least
200
- definition_manager = DefinitionManager(target_directory)
201
- if not definition_manager.has_definition_file:
202
- raise MissingConfiguration(
203
- "Cannot find project definition (snowflake.yml). Please provide a path to the project or run this command in a valid project directory."
204
- )
205
-
206
- # 2. Change the project name in snowflake.yml if necessary
207
- _replace_snowflake_yml_name_with_project(
208
- target_directory=target_directory, project_identifier=project_identifier
209
- )
210
-
211
- # 3. Validate the Project Definition File(s)
212
- definition_manager.project_definition
213
-
214
-
215
- def _generate_project_name_from_path(p: Path):
216
- return re.sub(r"[. -]+", "_", p.name)
217
-
218
-
219
- def _init_from_template(
220
- project_path: Path,
221
- project_identifier: str,
222
- git_url: Optional[str],
223
- template: Optional[str],
224
- ):
225
- """
226
- Initialize a Snowflake Native App project with a git URL and optionally a specific template within the git URL.
227
-
228
- Args:
229
- project_path (Path): The directory of the user where the project will be added.
230
- project_identifier (str): The name of the project to be created, as a Snowflake identifier.
231
- git_url (str): The git URL to perform a clone from.
232
- template (str): A optional template within the git URL to use, all other directories and files outside the
233
- template will be discarded.
234
-
235
- Returns:
236
- None
237
- """
238
- use_whole_repo_as_template = git_url and not template
239
- if not use_whole_repo_as_template:
240
- git_url = git_url if git_url else OFFICIAL_TEMPLATES_GITHUB_URL
241
-
242
- try:
243
- with SecurePath.temporary_directory() as temp_path:
244
- from git import rmtree as git_rmtree
245
- from snowflake.cli._plugins.nativeapp.utils import shallow_git_clone
246
-
247
- shallow_git_clone(git_url, temp_path.path)
248
-
249
- if use_whole_repo_as_template:
250
- # the template is the entire git repository
251
- template_root = temp_path
252
- # Remove all git history before we move the repo
253
- git_rmtree((template_root / ".git").path)
254
- else:
255
- # The template is a subdirectory of the git repository
256
- template_name = template if template else BASIC_TEMPLATE
257
- template_root = temp_path / template_name
258
- if not template_root.path.is_dir():
259
- raise TemplateNotFoundError(template_name=template_name)
260
-
261
- if (template_root / "snowflake.yml.jinja").exists():
262
- # Render snowflake.yml file from its jinja template
263
- _render_snowflake_yml(
264
- parent_to_snowflake_yml=template_root.path,
265
- project_identifier=project_identifier,
266
- )
267
-
268
- # If not an official Snowflake Native App template
269
- if git_url != OFFICIAL_TEMPLATES_GITHUB_URL:
270
- _validate_and_update_snowflake_yml(
271
- target_directory=template_root.path,
272
- project_identifier=project_identifier,
273
- )
274
-
275
- project_path.parent.mkdir(parents=True, exist_ok=True)
276
-
277
- # Move the template to the specified path
278
- template_root.move(project_path)
279
-
280
- except TemplateNotFoundError:
281
- raise
282
- except Exception as err:
283
- # If there was any error, validation on Project Definition file or otherwise,
284
- # there should not be any Snowflake Native App Project left after this.
285
- if project_path.exists():
286
- SecurePath(project_path).rmdir(recursive=True)
287
-
288
- log.error(err)
289
- raise InitError()
290
-
291
-
292
- def nativeapp_init(
293
- path: str,
294
- name: Optional[str] = None,
295
- git_url: Optional[str] = None,
296
- template: Optional[str] = None,
297
- ) -> ProjectDescriptor:
298
- """
299
- Initialize a Snowflake Native App project in the user's current working directory, with or without the use of a template.
300
-
301
- Args:
302
- path (str): The location of the project to be created.
303
- name (str): Name of the project to be created.
304
- git_url (str): The git URL to perform a clone from.
305
- template (str): A template within the git URL to use, all other directories and files outside the template will be discarded.
306
-
307
- Returns:
308
- A project descriptor for the newly initialized project.
309
- """
310
- try:
311
- project_path = Path(path).expanduser().resolve()
312
- except Exception as err: # expanduser can fail
313
- raise InitError()
314
-
315
- # If a subdirectory with the same name as name exists in the current directory, fail init command
316
- if project_path.exists():
317
- raise DirectoryAlreadyExistsError(path)
318
-
319
- # Check if the specified path already exists in a Snowflake Native App project. Nesting projects is not allowed.
320
- if DefinitionManager.find_project_root(search_path=project_path.parent) is not None:
321
- raise CannotInitializeAnExistingProjectError()
322
-
323
- project_name = (
324
- name if name is not None else _generate_project_name_from_path(project_path)
325
- )
326
- if not project_name:
327
- # empty name
328
- raise ProjectNameInvalidError(project_name=project_name)
329
-
330
- if not is_valid_identifier(project_name) and (
331
- project_name.startswith('"') or project_name.endswith('"')
332
- ):
333
- # the project name looks like it was partially quoted. This is likely a mistake, reject it rather than
334
- # silently escaping it.
335
- raise ProjectNameInvalidError(project_name=project_name)
336
-
337
- project_identifier = to_identifier(project_name)
338
- _init_from_template(
339
- project_path=project_path,
340
- project_identifier=project_identifier,
341
- git_url=git_url,
342
- template=template,
343
- )
344
-
345
- return ProjectDescriptor(name=project_name, path=project_path)