snowflake-cli-labs 3.0.0rc0__py3-none-any.whl → 3.0.0rc2__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 (66) hide show
  1. snowflake/cli/__about__.py +1 -1
  2. snowflake/cli/_app/cli_app.py +10 -1
  3. snowflake/cli/_app/snow_connector.py +91 -37
  4. snowflake/cli/_app/telemetry.py +8 -4
  5. snowflake/cli/_app/version_check.py +74 -0
  6. snowflake/cli/_plugins/connection/commands.py +3 -2
  7. snowflake/cli/_plugins/git/commands.py +55 -14
  8. snowflake/cli/_plugins/git/manager.py +14 -6
  9. snowflake/cli/_plugins/nativeapp/codegen/compiler.py +18 -2
  10. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +123 -42
  11. snowflake/cli/_plugins/nativeapp/codegen/setup/setup_driver.py.source +5 -2
  12. snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +6 -11
  13. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +111 -0
  14. snowflake/cli/_plugins/nativeapp/exceptions.py +3 -3
  15. snowflake/cli/_plugins/nativeapp/manager.py +74 -144
  16. snowflake/cli/_plugins/nativeapp/project_model.py +2 -9
  17. snowflake/cli/_plugins/nativeapp/run_processor.py +56 -260
  18. snowflake/cli/_plugins/nativeapp/same_account_install_method.py +74 -0
  19. snowflake/cli/_plugins/nativeapp/teardown_processor.py +17 -246
  20. snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +91 -17
  21. snowflake/cli/_plugins/snowpark/commands.py +5 -65
  22. snowflake/cli/_plugins/snowpark/common.py +17 -1
  23. snowflake/cli/_plugins/snowpark/models.py +2 -1
  24. snowflake/cli/_plugins/snowpark/package/anaconda_packages.py +1 -35
  25. snowflake/cli/_plugins/sql/commands.py +1 -2
  26. snowflake/cli/_plugins/stage/commands.py +2 -2
  27. snowflake/cli/_plugins/stage/manager.py +46 -15
  28. snowflake/cli/_plugins/streamlit/commands.py +4 -63
  29. snowflake/cli/_plugins/streamlit/manager.py +13 -0
  30. snowflake/cli/_plugins/workspace/action_context.py +7 -0
  31. snowflake/cli/_plugins/workspace/commands.py +145 -32
  32. snowflake/cli/_plugins/workspace/manager.py +21 -4
  33. snowflake/cli/api/cli_global_context.py +136 -313
  34. snowflake/cli/api/commands/decorators.py +1 -1
  35. snowflake/cli/api/commands/flags.py +106 -102
  36. snowflake/cli/api/commands/snow_typer.py +15 -6
  37. snowflake/cli/api/config.py +18 -5
  38. snowflake/cli/api/connections.py +214 -0
  39. snowflake/cli/api/console/abc.py +4 -2
  40. snowflake/cli/api/constants.py +11 -0
  41. snowflake/cli/api/entities/application_entity.py +687 -2
  42. snowflake/cli/api/entities/application_package_entity.py +407 -9
  43. snowflake/cli/api/entities/common.py +7 -2
  44. snowflake/cli/api/entities/utils.py +80 -20
  45. snowflake/cli/api/exceptions.py +12 -2
  46. snowflake/cli/api/feature_flags.py +0 -2
  47. snowflake/cli/api/identifiers.py +3 -0
  48. snowflake/cli/api/project/definition.py +35 -1
  49. snowflake/cli/api/project/definition_conversion.py +352 -0
  50. snowflake/cli/api/project/schemas/entities/application_package_entity_model.py +17 -0
  51. snowflake/cli/api/project/schemas/entities/common.py +0 -12
  52. snowflake/cli/api/project/schemas/identifier_model.py +2 -2
  53. snowflake/cli/api/project/schemas/project_definition.py +102 -43
  54. snowflake/cli/api/rendering/jinja.py +2 -16
  55. snowflake/cli/api/rendering/project_definition_templates.py +5 -1
  56. snowflake/cli/api/rendering/sql_templates.py +14 -4
  57. snowflake/cli/api/secure_path.py +13 -18
  58. snowflake/cli/api/secure_utils.py +90 -1
  59. snowflake/cli/api/sql_execution.py +13 -0
  60. snowflake/cli/api/utils/definition_rendering.py +7 -7
  61. {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/METADATA +9 -9
  62. {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/RECORD +65 -61
  63. snowflake/cli/api/commands/typer_pre_execute.py +0 -26
  64. {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/WHEEL +0 -0
  65. {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/entry_points.txt +0 -0
  66. {snowflake_cli_labs-3.0.0rc0.dist-info → snowflake_cli_labs-3.0.0rc2.dist-info}/licenses/LICENSE +0 -0
@@ -14,32 +14,20 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- import json
18
17
  import time
19
18
  from abc import ABC, abstractmethod
20
- from contextlib import contextmanager
21
19
  from datetime import datetime
22
20
  from functools import cached_property
23
21
  from pathlib import Path
24
22
  from textwrap import dedent
25
- from typing import Generator, List, Optional, TypedDict
23
+ from typing import Generator, List, Optional
26
24
 
27
- from click import ClickException
28
25
  from snowflake.cli._plugins.connection.util import make_snowsight_url
29
26
  from snowflake.cli._plugins.nativeapp.artifacts import (
30
27
  BundleMap,
31
- build_bundle,
32
- )
33
- from snowflake.cli._plugins.nativeapp.codegen.compiler import (
34
- NativeAppCompiler,
35
- )
36
- from snowflake.cli._plugins.nativeapp.constants import (
37
- NAME_COL,
38
28
  )
39
29
  from snowflake.cli._plugins.nativeapp.exceptions import (
40
- ApplicationPackageDoesNotExistError,
41
30
  NoEventTableForAccount,
42
- SetupScriptFailedValidation,
43
31
  )
44
32
  from snowflake.cli._plugins.nativeapp.project_model import (
45
33
  NativeAppProjectModel,
@@ -47,8 +35,11 @@ from snowflake.cli._plugins.nativeapp.project_model import (
47
35
  from snowflake.cli._plugins.stage.diff import (
48
36
  DiffResult,
49
37
  )
50
- from snowflake.cli._plugins.stage.manager import StageManager
51
38
  from snowflake.cli.api.console import cli_console as cc
39
+ from snowflake.cli.api.entities.application_entity import (
40
+ ApplicationEntity,
41
+ ApplicationOwnedObject,
42
+ )
52
43
  from snowflake.cli.api.entities.application_package_entity import (
53
44
  ApplicationPackageEntity,
54
45
  )
@@ -57,10 +48,6 @@ from snowflake.cli.api.entities.utils import (
57
48
  generic_sql_error_handler,
58
49
  sync_deploy_root_with_stage,
59
50
  )
60
- from snowflake.cli.api.errno import (
61
- DOES_NOT_EXIST_OR_NOT_AUTHORIZED,
62
- )
63
- from snowflake.cli.api.exceptions import SnowflakeSQLExecutionError
64
51
  from snowflake.cli.api.project.schemas.entities.common import PostDeployHook
65
52
  from snowflake.cli.api.project.schemas.native_app.native_app import NativeApp
66
53
  from snowflake.cli.api.project.schemas.native_app.path_mapping import PathMapping
@@ -71,8 +58,6 @@ from snowflake.cli.api.project.util import (
71
58
  from snowflake.cli.api.sql_execution import SqlExecutionMixin
72
59
  from snowflake.connector import DictCursor, ProgrammingError
73
60
 
74
- ApplicationOwnedObject = TypedDict("ApplicationOwnedObject", {"name": str, "type": str})
75
-
76
61
 
77
62
  class NativeAppCommandProcessor(ABC):
78
63
  @abstractmethod
@@ -149,20 +134,8 @@ class NativeAppManager(SqlExecutionMixin):
149
134
  def application_warehouse(self) -> Optional[str]:
150
135
  return self.na_project.application_warehouse
151
136
 
152
- @contextmanager
153
137
  def use_application_warehouse(self):
154
- if self.application_warehouse:
155
- with self.use_warehouse(self.application_warehouse):
156
- yield
157
- else:
158
- raise ClickException(
159
- dedent(
160
- f"""\
161
- Application warehouse cannot be empty.
162
- Please provide a value for it in your connection information or your project definition file.
163
- """
164
- )
165
- )
138
+ return ApplicationEntity.use_application_warehouse(self.application_warehouse)
166
139
 
167
140
  @property
168
141
  def project_identifier(self) -> str:
@@ -227,10 +200,14 @@ class NativeAppManager(SqlExecutionMixin):
227
200
  """
228
201
  Populates the local deploy root from artifact sources.
229
202
  """
230
- bundle_map = build_bundle(self.project_root, self.deploy_root, self.artifacts)
231
- compiler = NativeAppCompiler(self.na_project.get_bundle_context())
232
- compiler.compile_artifacts()
233
- return bundle_map
203
+ return ApplicationPackageEntity.bundle(
204
+ project_root=self.project_root,
205
+ deploy_root=self.deploy_root,
206
+ bundle_root=self.bundle_root,
207
+ generated_root=self.generated_root,
208
+ package_name=self.package_name,
209
+ artifacts=self.artifacts,
210
+ )
234
211
 
235
212
  def sync_deploy_root_with_stage(
236
213
  self,
@@ -257,14 +234,10 @@ class NativeAppManager(SqlExecutionMixin):
257
234
  )
258
235
 
259
236
  def get_existing_app_info(self) -> Optional[dict]:
260
- """
261
- Check for an existing application object by the same name as in project definition, in account.
262
- It executes a 'show applications like' query and returns the result as single row, if one exists.
263
- """
264
- with self.use_role(self.app_role):
265
- return self.show_specific_object(
266
- "applications", self.app_name, name_col=NAME_COL
267
- )
237
+ return ApplicationEntity.get_existing_app_info(
238
+ app_name=self.app_name,
239
+ app_role=self.app_role,
240
+ )
268
241
 
269
242
  def get_existing_app_pkg_info(self) -> Optional[dict]:
270
243
  return ApplicationPackageEntity.get_existing_app_pkg_info(
@@ -272,32 +245,19 @@ class NativeAppManager(SqlExecutionMixin):
272
245
  package_role=self.package_role,
273
246
  )
274
247
 
275
- def get_objects_owned_by_application(self) -> List[ApplicationOwnedObject]:
276
- """
277
- Returns all application objects owned by this application.
278
- """
279
- with self.use_role(self.app_role):
280
- results = self._execute_query(
281
- f"show objects owned by application {self.app_name}"
282
- ).fetchall()
283
- return [{"name": row[1], "type": row[2]} for row in results]
248
+ def get_objects_owned_by_application(self):
249
+ return ApplicationEntity.get_objects_owned_by_application(
250
+ app_name=self.app_name,
251
+ app_role=self.app_role,
252
+ )
284
253
 
285
254
  def _application_objects_to_str(
286
255
  self, application_objects: list[ApplicationOwnedObject]
287
256
  ) -> str:
288
- """
289
- Returns a list in an "(Object Type) Object Name" format. Database-level and schema-level object names are fully qualified:
290
- (COMPUTE_POOL) POOL_NAME
291
- (DATABASE) DB_NAME
292
- (SCHEMA) DB_NAME.PUBLIC
293
- ...
294
- """
295
- return "\n".join(
296
- [self._application_object_to_str(obj) for obj in application_objects]
297
- )
257
+ return ApplicationEntity.application_objects_to_str(application_objects)
298
258
 
299
- def _application_object_to_str(self, obj: ApplicationOwnedObject) -> str:
300
- return f"({obj['type']}) {obj['name']}"
259
+ def _application_object_to_str(self, obj: ApplicationOwnedObject):
260
+ return ApplicationEntity.application_object_to_str(obj)
301
261
 
302
262
  def get_snowsight_url(self) -> str:
303
263
  """Returns the URL that can be used to visit this app via Snowsight."""
@@ -351,89 +311,59 @@ class NativeAppManager(SqlExecutionMixin):
351
311
  validate: bool = True,
352
312
  print_diff: bool = True,
353
313
  ) -> DiffResult:
354
- """app deploy process"""
355
-
356
- # 1. Create an empty application package, if none exists
357
- self.create_app_package()
358
-
359
- with self.use_role(self.package_role):
360
- # 2. now that the application package exists, create shared data
361
- self._apply_package_scripts()
362
-
363
- # 3. Upload files from deploy root local folder to the above stage
364
- stage_fqn = stage_fqn or self.stage_fqn
365
- diff = self.sync_deploy_root_with_stage(
366
- bundle_map=bundle_map,
367
- role=self.package_role,
368
- prune=prune,
369
- recursive=recursive,
370
- stage_fqn=stage_fqn,
371
- local_paths_to_sync=local_paths_to_sync,
372
- print_diff=print_diff,
373
- )
374
-
375
- # 4. Execute post-deploy hooks
376
- with self.use_package_warehouse():
377
- self.execute_package_post_deploy_hooks()
378
-
379
- if validate:
380
- self.validate(use_scratch_stage=False)
314
+ return ApplicationPackageEntity.deploy(
315
+ console=cc,
316
+ project_root=self.project_root,
317
+ deploy_root=self.deploy_root,
318
+ bundle_root=self.bundle_root,
319
+ generated_root=self.generated_root,
320
+ artifacts=self.artifacts,
321
+ package_name=self.package_name,
322
+ package_role=self.package_role,
323
+ package_distribution=self.package_distribution,
324
+ prune=prune,
325
+ recursive=recursive,
326
+ paths=local_paths_to_sync,
327
+ print_diff=print_diff,
328
+ validate=validate,
329
+ stage_fqn=stage_fqn or self.stage_fqn,
330
+ package_warehouse=self.package_warehouse,
331
+ post_deploy_hooks=self.package_post_deploy_hooks,
332
+ package_scripts=self.package_scripts,
333
+ )
381
334
 
382
- return diff
335
+ def deploy_to_scratch_stage_fn(self):
336
+ bundle_map = self.build_bundle()
337
+ self.deploy(
338
+ bundle_map=bundle_map,
339
+ prune=True,
340
+ recursive=True,
341
+ stage_fqn=self.scratch_stage_fqn,
342
+ validate=False,
343
+ print_diff=False,
344
+ )
383
345
 
384
346
  def validate(self, use_scratch_stage: bool = False):
385
- """Validates Native App setup script SQL."""
386
- with cc.phase(f"Validating Snowflake Native App setup script."):
387
- validation_result = self.get_validation_result(use_scratch_stage)
388
-
389
- # First print warnings, regardless of the outcome of validation
390
- for warning in validation_result.get("warnings", []):
391
- cc.warning(_validation_item_to_str(warning))
392
-
393
- # Then print errors
394
- for error in validation_result.get("errors", []):
395
- # Print them as warnings for now since we're going to be
396
- # revamping CLI output soon
397
- cc.warning(_validation_item_to_str(error))
398
-
399
- # Then raise an exception if validation failed
400
- if validation_result["status"] == "FAIL":
401
- raise SetupScriptFailedValidation()
347
+ return ApplicationPackageEntity.validate_setup_script(
348
+ console=cc,
349
+ package_name=self.package_name,
350
+ package_role=self.package_role,
351
+ stage_fqn=self.stage_fqn,
352
+ use_scratch_stage=use_scratch_stage,
353
+ scratch_stage_fqn=self.scratch_stage_fqn,
354
+ deploy_to_scratch_stage_fn=self.deploy_to_scratch_stage_fn,
355
+ )
402
356
 
403
357
  def get_validation_result(self, use_scratch_stage: bool):
404
- """Call system$validate_native_app_setup() to validate deployed Native App setup script."""
405
- stage_fqn = self.stage_fqn
406
- if use_scratch_stage:
407
- stage_fqn = self.scratch_stage_fqn
408
- bundle_map = self.build_bundle()
409
- self.deploy(
410
- bundle_map=bundle_map,
411
- prune=True,
412
- recursive=True,
413
- stage_fqn=stage_fqn,
414
- validate=False,
415
- print_diff=False,
416
- )
417
- prefixed_stage_fqn = StageManager.get_standard_stage_prefix(stage_fqn)
418
- try:
419
- cursor = self._execute_query(
420
- f"call system$validate_native_app_setup('{prefixed_stage_fqn}')"
421
- )
422
- except ProgrammingError as err:
423
- if err.errno == DOES_NOT_EXIST_OR_NOT_AUTHORIZED:
424
- raise ApplicationPackageDoesNotExistError(self.package_name)
425
- generic_sql_error_handler(err)
426
- else:
427
- if not cursor.rowcount:
428
- raise SnowflakeSQLExecutionError()
429
- return json.loads(cursor.fetchone()[0])
430
- finally:
431
- if use_scratch_stage:
432
- cc.step(f"Dropping stage {self.scratch_stage_fqn}.")
433
- with self.use_role(self.package_role):
434
- self._execute_query(
435
- f"drop stage if exists {self.scratch_stage_fqn}"
436
- )
358
+ return ApplicationPackageEntity.get_validation_result(
359
+ console=cc,
360
+ package_name=self.package_name,
361
+ package_role=self.package_role,
362
+ stage_fqn=self.stage_fqn,
363
+ use_scratch_stage=use_scratch_stage,
364
+ scratch_stage_fqn=self.scratch_stage_fqn,
365
+ deploy_to_scratch_stage_fn=self.deploy_to_scratch_stage_fn,
366
+ )
437
367
 
438
368
  def get_events( # type: ignore [return]
439
369
  self,
@@ -21,6 +21,7 @@ from typing import List, Optional
21
21
  from snowflake.cli._plugins.nativeapp.artifacts import resolve_without_follow
22
22
  from snowflake.cli._plugins.nativeapp.bundle_context import BundleContext
23
23
  from snowflake.cli.api.cli_global_context import get_cli_context
24
+ from snowflake.cli.api.entities.common import get_sql_executor
24
25
  from snowflake.cli.api.project.definition import (
25
26
  default_app_package,
26
27
  default_application,
@@ -34,14 +35,6 @@ from snowflake.cli.api.project.util import (
34
35
  extract_schema,
35
36
  to_identifier,
36
37
  )
37
- from snowflake.connector import DictCursor
38
-
39
-
40
- def current_role() -> str:
41
- conn = get_cli_context().connection
42
- *_, cursor = conn.execute_string("select current_role()", cursor_class=DictCursor)
43
- role_result = cursor.fetchone()
44
- return role_result["CURRENT_ROLE()"]
45
38
 
46
39
 
47
40
  class NativeAppProjectModel:
@@ -198,7 +191,7 @@ class NativeAppProjectModel:
198
191
  def _default_role(self) -> str:
199
192
  role = default_role()
200
193
  if role is None:
201
- role = current_role()
194
+ role = get_sql_executor().current_role()
202
195
  return role
203
196
 
204
197
  @cached_property