snowflake-cli-labs 2.8.0rc1__py3-none-any.whl → 3.0.0rc1__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 (224) hide show
  1. snowflake/cli/__about__.py +1 -1
  2. snowflake/cli/{app → _app}/__main__.py +1 -1
  3. snowflake/cli/{app → _app}/cli_app.py +12 -12
  4. snowflake/cli/{app → _app}/commands_registration/builtin_plugins.py +13 -19
  5. snowflake/cli/{app → _app}/commands_registration/command_plugins_loader.py +9 -9
  6. snowflake/cli/{app → _app}/commands_registration/commands_registration_with_callbacks.py +4 -4
  7. snowflake/cli/{app → _app}/commands_registration/exception_logging.py +2 -2
  8. snowflake/cli/{app → _app}/commands_registration/typer_registration.py +2 -2
  9. snowflake/cli/{app → _app}/dev/docs/commands_docs_generator.py +30 -12
  10. snowflake/cli/{app → _app}/dev/docs/generator.py +3 -3
  11. snowflake/cli/{app → _app}/dev/docs/project_definition_docs_generator.py +4 -4
  12. snowflake/cli/{app → _app}/dev/docs/templates/usage.rst.jinja2 +14 -4
  13. snowflake/cli/{app → _app}/main_typer.py +2 -2
  14. snowflake/cli/{app → _app}/printing.py +2 -2
  15. snowflake/cli/{app → _app}/snow_connector.py +24 -17
  16. snowflake/cli/{app → _app}/telemetry.py +4 -5
  17. snowflake/cli/{plugins → _plugins}/connection/commands.py +25 -7
  18. snowflake/cli/_plugins/connection/plugin_spec.py +30 -0
  19. snowflake/cli/{plugins → _plugins}/connection/util.py +16 -0
  20. snowflake/cli/{plugins → _plugins}/cortex/commands.py +54 -49
  21. snowflake/cli/{plugins → _plugins}/cortex/constants.py +1 -1
  22. snowflake/cli/{plugins → _plugins}/cortex/manager.py +5 -5
  23. snowflake/cli/{plugins → _plugins}/cortex/plugin_spec.py +1 -1
  24. snowflake/cli/{plugins → _plugins}/git/commands.py +32 -20
  25. snowflake/cli/{plugins → _plugins}/git/manager.py +20 -11
  26. snowflake/cli/{plugins → _plugins}/git/plugin_spec.py +1 -1
  27. snowflake/cli/{plugins → _plugins}/init/commands.py +10 -6
  28. snowflake/cli/{plugins → _plugins}/init/plugin_spec.py +1 -1
  29. snowflake/cli/{plugins → _plugins}/nativeapp/artifacts.py +14 -0
  30. snowflake/cli/_plugins/nativeapp/bundle_context.py +31 -0
  31. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/artifact_processor.py +3 -3
  32. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/compiler.py +32 -18
  33. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +249 -0
  34. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/setup/setup_driver.py.source +5 -2
  35. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/extension_function_utils.py +4 -4
  36. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/python_processor.py +23 -29
  37. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +93 -0
  38. snowflake/cli/{plugins → _plugins}/nativeapp/commands.py +171 -42
  39. snowflake/cli/{plugins → _plugins}/nativeapp/common_flags.py +1 -1
  40. snowflake/cli/{plugins → _plugins}/nativeapp/exceptions.py +3 -3
  41. snowflake/cli/{plugins → _plugins}/nativeapp/init.py +1 -1
  42. snowflake/cli/_plugins/nativeapp/manager.py +572 -0
  43. snowflake/cli/{plugins/connection → _plugins/nativeapp}/plugin_spec.py +1 -1
  44. snowflake/cli/{plugins → _plugins}/nativeapp/project_model.py +35 -19
  45. snowflake/cli/{plugins → _plugins}/nativeapp/run_processor.py +25 -23
  46. snowflake/cli/{plugins → _plugins}/nativeapp/teardown_processor.py +24 -110
  47. snowflake/cli/{plugins → _plugins}/nativeapp/v2_conversions/v2_to_v1_decorator.py +47 -28
  48. snowflake/cli/{plugins → _plugins}/nativeapp/version/commands.py +15 -12
  49. snowflake/cli/{plugins → _plugins}/nativeapp/version/version_processor.py +22 -20
  50. snowflake/cli/{plugins → _plugins}/notebook/commands.py +8 -6
  51. snowflake/cli/{plugins → _plugins}/notebook/manager.py +14 -14
  52. snowflake/cli/{plugins → _plugins}/notebook/plugin_spec.py +1 -1
  53. snowflake/cli/{plugins → _plugins}/notebook/types.py +0 -1
  54. snowflake/cli/{plugins → _plugins}/object/command_aliases.py +6 -5
  55. snowflake/cli/{plugins → _plugins}/object/commands.py +16 -10
  56. snowflake/cli/{plugins → _plugins}/object/manager.py +7 -6
  57. snowflake/cli/{plugins → _plugins}/object/plugin_spec.py +1 -1
  58. snowflake/cli/_plugins/snowpark/commands.py +450 -0
  59. snowflake/cli/_plugins/snowpark/common.py +268 -0
  60. snowflake/cli/{plugins → _plugins}/snowpark/models.py +0 -7
  61. snowflake/cli/{plugins → _plugins}/snowpark/package/anaconda_packages.py +2 -36
  62. snowflake/cli/{plugins → _plugins}/snowpark/package/commands.py +13 -74
  63. snowflake/cli/{plugins → _plugins}/snowpark/package/manager.py +4 -3
  64. snowflake/cli/{plugins → _plugins}/snowpark/package_utils.py +5 -5
  65. snowflake/cli/{plugins/nativeapp → _plugins/snowpark}/plugin_spec.py +1 -1
  66. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +109 -0
  67. snowflake/cli/{plugins → _plugins}/snowpark/snowpark_shared.py +0 -36
  68. snowflake/cli/{plugins → _plugins}/snowpark/zipper.py +16 -8
  69. snowflake/cli/{plugins → _plugins}/spcs/__init__.py +5 -7
  70. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/commands.py +29 -28
  71. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/manager.py +3 -3
  72. snowflake/cli/{plugins → _plugins}/spcs/image_registry/commands.py +3 -3
  73. snowflake/cli/{plugins → _plugins}/spcs/image_repository/commands.py +25 -19
  74. snowflake/cli/{plugins → _plugins}/spcs/image_repository/manager.py +1 -1
  75. snowflake/cli/{plugins → _plugins}/spcs/plugin_spec.py +1 -1
  76. snowflake/cli/{plugins → _plugins}/spcs/services/commands.py +66 -32
  77. snowflake/cli/{plugins → _plugins}/spcs/services/manager.py +43 -5
  78. snowflake/cli/{plugins → _plugins}/sql/commands.py +20 -17
  79. snowflake/cli/{plugins → _plugins}/sql/manager.py +1 -1
  80. snowflake/cli/{plugins → _plugins}/sql/plugin_spec.py +1 -1
  81. snowflake/cli/{plugins → _plugins}/stage/commands.py +20 -17
  82. snowflake/cli/{plugins → _plugins}/stage/diff.py +1 -47
  83. snowflake/cli/{plugins → _plugins}/stage/manager.py +54 -21
  84. snowflake/cli/{plugins → _plugins}/stage/plugin_spec.py +1 -1
  85. snowflake/cli/_plugins/stage/utils.py +54 -0
  86. snowflake/cli/{plugins → _plugins}/streamlit/commands.py +59 -62
  87. snowflake/cli/{plugins → _plugins}/streamlit/manager.py +51 -70
  88. snowflake/cli/_plugins/streamlit/plugin_spec.py +30 -0
  89. snowflake/cli/_plugins/workspace/action_context.py +17 -0
  90. snowflake/cli/_plugins/workspace/commands.py +194 -0
  91. snowflake/cli/_plugins/workspace/manager.py +73 -0
  92. snowflake/cli/{plugins → _plugins}/workspace/plugin_spec.py +1 -1
  93. snowflake/cli/api/cli_global_context.py +40 -13
  94. snowflake/cli/api/commands/common.py +25 -0
  95. snowflake/cli/api/commands/decorators.py +5 -4
  96. snowflake/cli/api/commands/experimental_behaviour.py +2 -3
  97. snowflake/cli/api/commands/flags.py +97 -179
  98. snowflake/cli/api/commands/overrideable_parameter.py +143 -0
  99. snowflake/cli/api/commands/snow_typer.py +14 -6
  100. snowflake/cli/api/commands/typer_pre_execute.py +3 -3
  101. snowflake/cli/api/commands/utils.py +18 -0
  102. snowflake/cli/api/config.py +18 -5
  103. snowflake/cli/api/console/abc.py +5 -2
  104. snowflake/cli/api/constants.py +11 -0
  105. snowflake/cli/api/entities/application_entity.py +12 -0
  106. snowflake/cli/api/entities/application_package_entity.py +553 -0
  107. snowflake/cli/api/entities/common.py +51 -0
  108. snowflake/cli/api/entities/snowpark_entity.py +29 -0
  109. snowflake/cli/api/entities/streamlit_entity.py +12 -0
  110. snowflake/cli/api/entities/utils.py +357 -0
  111. snowflake/cli/api/exceptions.py +31 -5
  112. snowflake/cli/api/feature_flags.py +0 -1
  113. snowflake/cli/api/identifiers.py +41 -9
  114. snowflake/cli/api/project/definition.py +37 -6
  115. snowflake/cli/api/project/definition_conversion.py +194 -0
  116. snowflake/cli/api/project/definition_manager.py +12 -1
  117. snowflake/cli/api/project/project_verification.py +3 -3
  118. snowflake/cli/api/project/schemas/entities/{application_entity.py → application_entity_model.py} +21 -9
  119. snowflake/cli/api/project/schemas/entities/{application_package_entity.py → application_package_entity_model.py} +43 -15
  120. snowflake/cli/api/project/schemas/entities/common.py +80 -6
  121. snowflake/cli/api/project/schemas/entities/entities.py +38 -8
  122. snowflake/cli/api/project/schemas/entities/snowpark_entity.py +176 -0
  123. snowflake/cli/api/project/schemas/entities/streamlit_entity_model.py +73 -0
  124. snowflake/cli/api/project/schemas/identifier_model.py +10 -1
  125. snowflake/cli/api/project/schemas/native_app/application.py +8 -9
  126. snowflake/cli/api/project/schemas/native_app/package.py +7 -1
  127. snowflake/cli/api/project/schemas/project_definition.py +98 -27
  128. snowflake/cli/api/project/schemas/updatable_model.py +11 -3
  129. snowflake/cli/api/project/util.py +23 -6
  130. snowflake/cli/api/rendering/jinja.py +14 -8
  131. snowflake/cli/api/rendering/project_definition_templates.py +1 -1
  132. snowflake/cli/api/rendering/sql_templates.py +43 -11
  133. snowflake/cli/api/secure_path.py +16 -18
  134. snowflake/cli/api/secure_utils.py +90 -1
  135. snowflake/cli/api/sql_execution.py +48 -19
  136. snowflake/cli/api/utils/definition_rendering.py +18 -8
  137. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0rc1.dist-info}/METADATA +13 -13
  138. snowflake_cli_labs-3.0.0rc1.dist-info/RECORD +236 -0
  139. snowflake_cli_labs-3.0.0rc1.dist-info/entry_points.txt +2 -0
  140. snowflake/cli/api/commands/project_initialisation.py +0 -65
  141. snowflake/cli/app/build_and_push.sh +0 -8
  142. snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -172
  143. snowflake/cli/plugins/nativeapp/manager.py +0 -823
  144. snowflake/cli/plugins/object_stage_deprecated/__init__.py +0 -15
  145. snowflake/cli/plugins/object_stage_deprecated/commands.py +0 -122
  146. snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +0 -32
  147. snowflake/cli/plugins/snowpark/commands.py +0 -548
  148. snowflake/cli/plugins/snowpark/common.py +0 -307
  149. snowflake/cli/plugins/snowpark/manager.py +0 -109
  150. snowflake/cli/plugins/snowpark/plugin_spec.py +0 -30
  151. snowflake/cli/plugins/snowpark/snowpark_package_paths.py +0 -65
  152. snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
  153. snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
  154. snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
  155. snowflake/cli/plugins/workspace/commands.py +0 -35
  156. snowflake/cli/templates/default_snowpark/.gitignore +0 -4
  157. snowflake/cli/templates/default_snowpark/app/__init__.py +0 -0
  158. snowflake/cli/templates/default_snowpark/app/common.py +0 -2
  159. snowflake/cli/templates/default_snowpark/app/functions.py +0 -15
  160. snowflake/cli/templates/default_snowpark/app/procedures.py +0 -22
  161. snowflake/cli/templates/default_snowpark/requirements.txt +0 -1
  162. snowflake/cli/templates/default_snowpark/snowflake.yml +0 -23
  163. snowflake/cli/templates/default_streamlit/.gitignore +0 -4
  164. snowflake/cli/templates/default_streamlit/common/hello.py +0 -2
  165. snowflake/cli/templates/default_streamlit/environment.yml +0 -6
  166. snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -3
  167. snowflake/cli/templates/default_streamlit/snowflake.yml +0 -10
  168. snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -4
  169. snowflake_cli_labs-2.8.0rc1.dist-info/RECORD +0 -240
  170. snowflake_cli_labs-2.8.0rc1.dist-info/entry_points.txt +0 -2
  171. /snowflake/cli/{app → _app}/__init__.py +0 -0
  172. /snowflake/cli/{app → _app}/api_impl/__init__.py +0 -0
  173. /snowflake/cli/{app → _app}/api_impl/plugin/__init__.py +0 -0
  174. /snowflake/cli/{app → _app}/api_impl/plugin/plugin_config_provider_impl.py +0 -0
  175. /snowflake/cli/{app → _app}/commands_registration/__init__.py +0 -0
  176. /snowflake/cli/{app → _app}/commands_registration/threadsafe.py +0 -0
  177. /snowflake/cli/{app → _app}/constants.py +0 -0
  178. /snowflake/cli/{app → _app}/dev/__init__.py +0 -0
  179. /snowflake/cli/{app → _app}/dev/commands_structure.py +0 -0
  180. /snowflake/cli/{app → _app}/dev/docs/__init__.py +0 -0
  181. /snowflake/cli/{app → _app}/dev/docs/project_definition_generate_json_schema.py +0 -0
  182. /snowflake/cli/{app → _app}/dev/docs/template_utils.py +0 -0
  183. /snowflake/cli/{app → _app}/dev/docs/templates/definition_description.rst.jinja2 +0 -0
  184. /snowflake/cli/{app → _app}/dev/docs/templates/overview.rst.jinja2 +0 -0
  185. /snowflake/cli/{app → _app}/dev/pycharm_remote_debug.py +0 -0
  186. /snowflake/cli/{app → _app}/loggers.py +0 -0
  187. /snowflake/cli/{plugins → _plugins}/__init__.py +0 -0
  188. /snowflake/cli/{plugins → _plugins}/connection/__init__.py +0 -0
  189. /snowflake/cli/{plugins → _plugins}/cortex/__init__.py +0 -0
  190. /snowflake/cli/{plugins → _plugins}/cortex/types.py +0 -0
  191. /snowflake/cli/{plugins → _plugins}/git/__init__.py +0 -0
  192. /snowflake/cli/{plugins → _plugins}/init/__init__.py +0 -0
  193. /snowflake/cli/{plugins → _plugins}/nativeapp/__init__.py +0 -0
  194. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/__init__.py +0 -0
  195. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/sandbox.py +0 -0
  196. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -0
  197. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/models.py +0 -0
  198. /snowflake/cli/{plugins → _plugins}/nativeapp/constants.py +0 -0
  199. /snowflake/cli/{plugins → _plugins}/nativeapp/feature_flags.py +0 -0
  200. /snowflake/cli/{plugins → _plugins}/nativeapp/policy.py +0 -0
  201. /snowflake/cli/{plugins → _plugins}/nativeapp/utils.py +0 -0
  202. /snowflake/cli/{plugins → _plugins}/nativeapp/version/__init__.py +0 -0
  203. /snowflake/cli/{plugins → _plugins}/notebook/__init__.py +0 -0
  204. /snowflake/cli/{plugins → _plugins}/notebook/exceptions.py +0 -0
  205. /snowflake/cli/{plugins → _plugins}/object/__init__.py +0 -0
  206. /snowflake/cli/{plugins → _plugins}/object/common.py +0 -0
  207. /snowflake/cli/{plugins → _plugins}/snowpark/__init__.py +0 -0
  208. /snowflake/cli/{plugins → _plugins}/snowpark/package/__init__.py +0 -0
  209. /snowflake/cli/{plugins → _plugins}/snowpark/package/utils.py +0 -0
  210. /snowflake/cli/{plugins → _plugins}/spcs/common.py +0 -0
  211. /snowflake/cli/{plugins → _plugins}/spcs/compute_pool/__init__.py +0 -0
  212. /snowflake/cli/{plugins → _plugins}/spcs/image_registry/__init__.py +0 -0
  213. /snowflake/cli/{plugins → _plugins}/spcs/image_registry/manager.py +0 -0
  214. /snowflake/cli/{plugins → _plugins}/spcs/image_repository/__init__.py +0 -0
  215. /snowflake/cli/{plugins/spcs/jobs → _plugins/spcs/services}/__init__.py +0 -0
  216. /snowflake/cli/{plugins/spcs/services → _plugins/sql}/__init__.py +0 -0
  217. /snowflake/cli/{plugins → _plugins}/sql/snowsql_templating.py +0 -0
  218. /snowflake/cli/{plugins/sql → _plugins/stage}/__init__.py +0 -0
  219. /snowflake/cli/{plugins → _plugins}/stage/md5.py +0 -0
  220. /snowflake/cli/{plugins/stage → _plugins/streamlit}/__init__.py +0 -0
  221. /snowflake/cli/{plugins/streamlit → _plugins/workspace}/__init__.py +0 -0
  222. /snowflake/cli/{plugins/workspace → api/project/schemas/entities}/__init__.py +0 -0
  223. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0rc1.dist-info}/WHEEL +0 -0
  224. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0rc1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,31 @@
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 dataclasses import dataclass
16
+ from pathlib import Path
17
+ from typing import (
18
+ List,
19
+ )
20
+
21
+ from snowflake.cli.api.project.schemas.native_app.path_mapping import PathMapping
22
+
23
+
24
+ @dataclass
25
+ class BundleContext:
26
+ package_name: str
27
+ artifacts: List[PathMapping]
28
+ project_root: Path
29
+ bundle_root: Path
30
+ deploy_root: Path
31
+ generated_root: Path
@@ -19,11 +19,11 @@ from pathlib import Path
19
19
  from typing import Optional
20
20
 
21
21
  from click import ClickException
22
+ from snowflake.cli._plugins.nativeapp.bundle_context import BundleContext
22
23
  from snowflake.cli.api.project.schemas.native_app.path_mapping import (
23
24
  PathMapping,
24
25
  ProcessorMapping,
25
26
  )
26
- from snowflake.cli.plugins.nativeapp.project_model import NativeAppProjectModel
27
27
 
28
28
 
29
29
  class UnsupportedArtifactProcessorError(ClickException):
@@ -74,9 +74,9 @@ class ProjectFileContextManager:
74
74
  class ArtifactProcessor(ABC):
75
75
  def __init__(
76
76
  self,
77
- na_project: NativeAppProjectModel,
77
+ bundle_ctx: BundleContext,
78
78
  ) -> None:
79
- self._na_project = na_project
79
+ self._bundle_ctx = bundle_ctx
80
80
 
81
81
  @abstractmethod
82
82
  def process(
@@ -14,31 +14,39 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
+ import copy
18
+ import re
17
19
  from typing import Dict, Optional
18
20
 
19
- from snowflake.cli.api.console import cli_console as cc
20
- from snowflake.cli.api.project.schemas.native_app.path_mapping import (
21
- ProcessorMapping,
22
- )
23
- from snowflake.cli.plugins.nativeapp.codegen.artifact_processor import (
21
+ from click import ClickException
22
+ from snowflake.cli._plugins.nativeapp.bundle_context import BundleContext
23
+ from snowflake.cli._plugins.nativeapp.codegen.artifact_processor import (
24
24
  ArtifactProcessor,
25
25
  UnsupportedArtifactProcessorError,
26
26
  )
27
- from snowflake.cli.plugins.nativeapp.codegen.setup.native_app_setup_processor import (
27
+ from snowflake.cli._plugins.nativeapp.codegen.setup.native_app_setup_processor import (
28
28
  NativeAppSetupProcessor,
29
29
  )
30
- from snowflake.cli.plugins.nativeapp.codegen.snowpark.python_processor import (
30
+ from snowflake.cli._plugins.nativeapp.codegen.snowpark.python_processor import (
31
31
  SnowparkAnnotationProcessor,
32
32
  )
33
- from snowflake.cli.plugins.nativeapp.feature_flags import FeatureFlag
34
- from snowflake.cli.plugins.nativeapp.project_model import NativeAppProjectModel
33
+ from snowflake.cli._plugins.nativeapp.codegen.templates.templates_processor import (
34
+ TemplatesProcessor,
35
+ )
36
+ from snowflake.cli._plugins.nativeapp.feature_flags import FeatureFlag
37
+ from snowflake.cli.api.console import cli_console as cc
38
+ from snowflake.cli.api.project.schemas.native_app.path_mapping import (
39
+ ProcessorMapping,
40
+ )
35
41
 
36
42
  SNOWPARK_PROCESSOR = "snowpark"
37
- NA_SETUP_PROCESSOR = "native-app-setup"
43
+ NA_SETUP_PROCESSOR = "native app setup"
44
+ TEMPLATES_PROCESSOR = "templates"
38
45
 
39
46
  _REGISTERED_PROCESSORS_BY_NAME = {
40
47
  SNOWPARK_PROCESSOR: SnowparkAnnotationProcessor,
41
48
  NA_SETUP_PROCESSOR: NativeAppSetupProcessor,
49
+ TEMPLATES_PROCESSOR: TemplatesProcessor,
42
50
  }
43
51
 
44
52
 
@@ -53,9 +61,9 @@ class NativeAppCompiler:
53
61
 
54
62
  def __init__(
55
63
  self,
56
- na_project: NativeAppProjectModel,
64
+ bundle_ctx: BundleContext,
57
65
  ):
58
- self._na_project = na_project
66
+ self._bundle_ctx = bundle_ctx
59
67
  # dictionary of all processors created and shared between different artifact objects.
60
68
  self.cached_processors: Dict[str, ArtifactProcessor] = {}
61
69
 
@@ -69,12 +77,12 @@ class NativeAppCompiler:
69
77
  return
70
78
 
71
79
  with cc.phase("Invoking artifact processors"):
72
- if self._na_project.generated_root.exists():
80
+ if self._bundle_ctx.generated_root.exists():
73
81
  raise ClickException(
74
- f"Path {self._na_project.generated_root} already exists. Please choose a different name for your generated directory in the project definition file."
82
+ f"Path {self._bundle_ctx.generated_root} already exists. Please choose a different name for your generated directory in the project definition file."
75
83
  )
76
84
 
77
- for artifact in self._na_project.artifacts:
85
+ for artifact in self._bundle_ctx.artifacts:
78
86
  for processor in artifact.processors:
79
87
  if self._is_enabled(processor):
80
88
  artifact_processor = self._try_create_processor(
@@ -110,15 +118,21 @@ class NativeAppCompiler:
110
118
  # No registered processor with the specified name
111
119
  return None
112
120
 
113
- current_processor = processor_factory(
114
- na_project=self._na_project,
121
+ processor_ctx = copy.copy(self._bundle_ctx)
122
+ processor_subdirectory = re.sub(r"[^a-zA-Z0-9_$]", "_", processor_name)
123
+ processor_ctx.bundle_root = (
124
+ self._bundle_ctx.bundle_root / processor_subdirectory
125
+ )
126
+ processor_ctx.generated_root = (
127
+ self._bundle_ctx.generated_root / processor_subdirectory
115
128
  )
129
+ current_processor = processor_factory(processor_ctx)
116
130
  self.cached_processors[processor_name] = current_processor
117
131
 
118
132
  return current_processor
119
133
 
120
134
  def _should_invoke_processors(self):
121
- for artifact in self._na_project.artifacts:
135
+ for artifact in self._bundle_ctx.artifacts:
122
136
  for processor in artifact.processors:
123
137
  if self._is_enabled(processor):
124
138
  return True
@@ -0,0 +1,249 @@
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 json
18
+ import logging
19
+ import os.path
20
+ from pathlib import Path
21
+ from typing import List, Optional
22
+
23
+ import yaml
24
+ from click import ClickException
25
+ from snowflake.cli._plugins.nativeapp.artifacts import (
26
+ BundleMap,
27
+ find_manifest_file,
28
+ find_setup_script_file,
29
+ )
30
+ from snowflake.cli._plugins.nativeapp.codegen.artifact_processor import (
31
+ ArtifactProcessor,
32
+ is_python_file_artifact,
33
+ )
34
+ from snowflake.cli._plugins.nativeapp.codegen.sandbox import (
35
+ ExecutionEnvironmentType,
36
+ SandboxEnvBuilder,
37
+ execute_script_in_sandbox,
38
+ )
39
+ from snowflake.cli._plugins.stage.diff import to_stage_path
40
+ from snowflake.cli.api.console import cli_console as cc
41
+ from snowflake.cli.api.project.schemas.native_app.path_mapping import (
42
+ PathMapping,
43
+ ProcessorMapping,
44
+ )
45
+
46
+ DEFAULT_TIMEOUT = 30
47
+ DRIVER_PATH = Path(__file__).parent / "setup_driver.py.source"
48
+
49
+ log = logging.getLogger(__name__)
50
+
51
+
52
+ def safe_set(d: dict, *keys: str, **kwargs) -> None:
53
+ """
54
+ Sets a value in a nested dictionary structure, creating intermediate dictionaries as needed.
55
+ Sample usage:
56
+
57
+ d = {}
58
+ safe_set(d, "a", "b", "c", value=42)
59
+
60
+ d is now:
61
+ {
62
+ "a": {
63
+ "b": {
64
+ "c": 42
65
+ }
66
+ }
67
+ }
68
+ """
69
+ curr = d
70
+ for k in keys[:-1]:
71
+ curr = curr.setdefault(k, {})
72
+
73
+ curr[keys[-1]] = kwargs.get("value")
74
+
75
+
76
+ class NativeAppSetupProcessor(ArtifactProcessor):
77
+ def __init__(self, *args, **kwargs):
78
+ super().__init__(*args, **kwargs)
79
+
80
+ def process(
81
+ self,
82
+ artifact_to_process: PathMapping,
83
+ processor_mapping: Optional[ProcessorMapping],
84
+ **kwargs,
85
+ ) -> None:
86
+ """
87
+ Processes a Python setup script and generates the corresponding SQL commands.
88
+ """
89
+ bundle_map = BundleMap(
90
+ project_root=self._bundle_ctx.project_root,
91
+ deploy_root=self._bundle_ctx.deploy_root,
92
+ )
93
+ bundle_map.add(artifact_to_process)
94
+
95
+ self._create_or_update_sandbox()
96
+
97
+ cc.step("Processing Python setup files")
98
+
99
+ files_to_process = []
100
+ for src_file, dest_file in bundle_map.all_mappings(
101
+ absolute=True, expand_directories=True, predicate=is_python_file_artifact
102
+ ):
103
+ cc.message(
104
+ f"Found Python setup file: {src_file.relative_to(self._bundle_ctx.project_root)}"
105
+ )
106
+ files_to_process.append(src_file)
107
+
108
+ result = self._execute_in_sandbox(files_to_process)
109
+ if not result:
110
+ return # nothing to do
111
+
112
+ logs = result.get("logs", [])
113
+ for msg in logs:
114
+ log.debug(msg)
115
+
116
+ warnings = result.get("warnings", [])
117
+ for msg in warnings:
118
+ cc.warning(msg)
119
+
120
+ schema_version = result.get("schema_version")
121
+ if schema_version != "1":
122
+ raise ClickException(
123
+ f"Unsupported schema version returned from snowflake-app-python library: {schema_version}"
124
+ )
125
+
126
+ setup_script_mods = [
127
+ mod
128
+ for mod in result.get("modifications", [])
129
+ if mod.get("target") == "native_app:setup_script"
130
+ ]
131
+ if setup_script_mods:
132
+ self._edit_setup_sql(setup_script_mods)
133
+
134
+ manifest_mods = [
135
+ mod
136
+ for mod in result.get("modifications", [])
137
+ if mod.get("target") == "native_app:manifest"
138
+ ]
139
+ if manifest_mods:
140
+ self._edit_manifest(manifest_mods)
141
+
142
+ def _execute_in_sandbox(self, py_files: List[Path]) -> dict:
143
+ file_count = len(py_files)
144
+ cc.step(f"Processing {file_count} setup file{'s' if file_count > 1 else ''}")
145
+
146
+ manifest_path = find_manifest_file(deploy_root=self._bundle_ctx.deploy_root)
147
+
148
+ generated_root = self._bundle_ctx.generated_root
149
+ generated_root.mkdir(exist_ok=True, parents=True)
150
+
151
+ env_vars = {
152
+ "_SNOWFLAKE_CLI_PROJECT_PATH": str(self._bundle_ctx.project_root),
153
+ "_SNOWFLAKE_CLI_SETUP_FILES": os.pathsep.join(map(str, py_files)),
154
+ "_SNOWFLAKE_CLI_APP_NAME": str(self._bundle_ctx.package_name),
155
+ "_SNOWFLAKE_CLI_SQL_DEST_DIR": str(generated_root),
156
+ "_SNOWFLAKE_CLI_MANIFEST_PATH": str(manifest_path),
157
+ }
158
+
159
+ try:
160
+ result = execute_script_in_sandbox(
161
+ script_source=DRIVER_PATH.read_text(),
162
+ env_type=ExecutionEnvironmentType.VENV,
163
+ cwd=self._bundle_ctx.bundle_root,
164
+ timeout=DEFAULT_TIMEOUT,
165
+ path=self.sandbox_root,
166
+ env_vars=env_vars,
167
+ )
168
+ except Exception as e:
169
+ raise ClickException(
170
+ f"Exception while executing python setup script logic: {e}"
171
+ )
172
+
173
+ if result.returncode == 0:
174
+ return json.loads(result.stdout)
175
+ else:
176
+ raise ClickException(
177
+ f"Failed to execute python setup script logic: {result.stderr}"
178
+ )
179
+
180
+ def _edit_setup_sql(self, modifications: List[dict]) -> None:
181
+ cc.step("Patching setup script")
182
+ setup_file_path = find_setup_script_file(
183
+ deploy_root=self._bundle_ctx.deploy_root
184
+ )
185
+
186
+ with self.edit_file(setup_file_path) as f:
187
+ prepended = []
188
+ appended = []
189
+
190
+ for mod in modifications:
191
+ for inst in mod.get("instructions", []):
192
+ if inst.get("type") == "insert":
193
+ default_loc = inst.get("default_location")
194
+ if default_loc == "end":
195
+ appended.append(self._setup_mod_instruction_to_sql(inst))
196
+ elif default_loc == "start":
197
+ prepended.append(self._setup_mod_instruction_to_sql(inst))
198
+
199
+ if prepended or appended:
200
+ f.edited_contents = "\n".join(prepended + [f.contents] + appended)
201
+
202
+ def _edit_manifest(self, modifications: List[dict]) -> None:
203
+ cc.step("Patching manifest")
204
+ manifest_path = find_manifest_file(deploy_root=self._bundle_ctx.deploy_root)
205
+
206
+ with self.edit_file(manifest_path) as f:
207
+ manifest = yaml.safe_load(f.contents)
208
+
209
+ for mod in modifications:
210
+ for inst in mod.get("instructions", []):
211
+ if inst.get("type") == "set":
212
+ payload = inst.get("payload")
213
+ if payload:
214
+ key = payload.get("key")
215
+ value = payload.get("value")
216
+ safe_set(manifest, *key.split("."), value=value)
217
+ f.edited_contents = yaml.safe_dump(manifest, sort_keys=False)
218
+
219
+ def _setup_mod_instruction_to_sql(self, mod_inst: dict) -> str:
220
+ payload = mod_inst.get("payload")
221
+ if not payload:
222
+ raise ClickException("Unsupported instruction received: no payload found")
223
+
224
+ payload_type = payload.get("type")
225
+ if payload_type == "execute immediate":
226
+ file_path = payload.get("file_path")
227
+ if file_path:
228
+ sql_file_path = self._bundle_ctx.generated_root / file_path
229
+ return f"EXECUTE IMMEDIATE FROM '/{to_stage_path(sql_file_path.relative_to(self._bundle_ctx.deploy_root))}';"
230
+
231
+ raise ClickException(f"Unsupported instruction type received: {payload_type}")
232
+
233
+ @property
234
+ def sandbox_root(self):
235
+ return self._bundle_ctx.bundle_root / "venv"
236
+
237
+ def _create_or_update_sandbox(self):
238
+ sandbox_root = self.sandbox_root
239
+ env_builder = SandboxEnvBuilder(sandbox_root, with_pip=True)
240
+ if sandbox_root.exists():
241
+ cc.step("Virtual environment found")
242
+ else:
243
+ cc.step(
244
+ f"Creating virtual environment in {sandbox_root.relative_to(self._bundle_ctx.project_root)}"
245
+ )
246
+ env_builder.ensure_created()
247
+
248
+ # Temporarily fetch the library from a location specified via env vars
249
+ env_builder.pip_install(os.environ["SNOWFLAKE_APP_PYTHON_LOC"])
@@ -20,8 +20,11 @@ from pathlib import Path
20
20
  import snowflake.app.context as ctx
21
21
  from snowflake.app.sql import SQLGenerator
22
22
 
23
- ctx._project_path = os.environ["_SNOWFLAKE_CLI_PROJECT_PATH"]
24
- ctx._current_app_name = os.environ["_SNOWFLAKE_CLI_APP_NAME"]
23
+ ctx.configure("project_path", os.environ.get("_SNOWFLAKE_CLI_PROJECT_PATH", None))
24
+ ctx.configure("manifest_path", os.environ.get("_SNOWFLAKE_CLI_MANIFEST_PATH", None))
25
+ ctx.configure("current_app_name", os.environ.get("_SNOWFLAKE_CLI_APP_NAME", None))
26
+ ctx.configure("enable_sql_generation", True)
27
+
25
28
  __snowflake_internal_py_files = os.environ["_SNOWFLAKE_CLI_SETUP_FILES"].split(
26
29
  os.pathsep
27
30
  )
@@ -23,6 +23,10 @@ from typing import (
23
23
  )
24
24
 
25
25
  from click.exceptions import ClickException
26
+ from snowflake.cli._plugins.nativeapp.codegen.snowpark.models import (
27
+ ExtensionFunctionTypeEnum,
28
+ NativeAppExtensionFunction,
29
+ )
26
30
  from snowflake.cli.api.project.schemas.snowpark.argument import Argument
27
31
  from snowflake.cli.api.project.util import (
28
32
  is_valid_identifier,
@@ -30,10 +34,6 @@ from snowflake.cli.api.project.util import (
30
34
  to_identifier,
31
35
  to_string_literal,
32
36
  )
33
- from snowflake.cli.plugins.nativeapp.codegen.snowpark.models import (
34
- ExtensionFunctionTypeEnum,
35
- NativeAppExtensionFunction,
36
- )
37
37
 
38
38
  ASTDefNode = Union[ast.FunctionDef, ast.ClassDef]
39
39
 
@@ -21,26 +21,20 @@ from textwrap import dedent
21
21
  from typing import Any, Dict, List, Optional, Set
22
22
 
23
23
  from pydantic import ValidationError
24
- from snowflake.cli.api.console import cli_console as cc
25
- from snowflake.cli.api.project.schemas.native_app.path_mapping import (
26
- PathMapping,
27
- ProcessorMapping,
28
- )
29
- from snowflake.cli.api.rendering.jinja import jinja_render_from_file
30
- from snowflake.cli.plugins.nativeapp.artifacts import (
24
+ from snowflake.cli._plugins.nativeapp.artifacts import (
31
25
  BundleMap,
32
26
  find_setup_script_file,
33
27
  )
34
- from snowflake.cli.plugins.nativeapp.codegen.artifact_processor import (
28
+ from snowflake.cli._plugins.nativeapp.codegen.artifact_processor import (
35
29
  ArtifactProcessor,
36
30
  is_python_file_artifact,
37
31
  )
38
- from snowflake.cli.plugins.nativeapp.codegen.sandbox import (
32
+ from snowflake.cli._plugins.nativeapp.codegen.sandbox import (
39
33
  ExecutionEnvironmentType,
40
34
  SandboxExecutionError,
41
35
  execute_script_in_sandbox,
42
36
  )
43
- from snowflake.cli.plugins.nativeapp.codegen.snowpark.extension_function_utils import (
37
+ from snowflake.cli._plugins.nativeapp.codegen.snowpark.extension_function_utils import (
44
38
  deannotate_module_source,
45
39
  ensure_all_string_literals,
46
40
  ensure_string_literal,
@@ -49,12 +43,17 @@ from snowflake.cli.plugins.nativeapp.codegen.snowpark.extension_function_utils i
49
43
  get_sql_argument_signature,
50
44
  get_sql_object_type,
51
45
  )
52
- from snowflake.cli.plugins.nativeapp.codegen.snowpark.models import (
46
+ from snowflake.cli._plugins.nativeapp.codegen.snowpark.models import (
53
47
  ExtensionFunctionTypeEnum,
54
48
  NativeAppExtensionFunction,
55
49
  )
56
- from snowflake.cli.plugins.nativeapp.project_model import NativeAppProjectModel
57
- from snowflake.cli.plugins.stage.diff import to_stage_path
50
+ from snowflake.cli._plugins.stage.diff import to_stage_path
51
+ from snowflake.cli.api.console import cli_console as cc
52
+ from snowflake.cli.api.project.schemas.native_app.path_mapping import (
53
+ PathMapping,
54
+ ProcessorMapping,
55
+ )
56
+ from snowflake.cli.api.rendering.jinja import jinja_render_from_file
58
57
 
59
58
  DEFAULT_TIMEOUT = 30
60
59
  TEMPLATE_PATH = Path(__file__).parent / "callback_source.py.jinja"
@@ -163,11 +162,8 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
163
162
  and generate SQL code for creation of extension functions based on those discovered objects.
164
163
  """
165
164
 
166
- def __init__(
167
- self,
168
- na_project: NativeAppProjectModel,
169
- ):
170
- super().__init__(na_project=na_project)
165
+ def __init__(self, *args, **kwargs):
166
+ super().__init__(*args, **kwargs)
171
167
 
172
168
  def process(
173
169
  self,
@@ -181,8 +177,8 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
181
177
  """
182
178
 
183
179
  bundle_map = BundleMap(
184
- project_root=self._na_project.project_root,
185
- deploy_root=self._na_project.deploy_root,
180
+ project_root=self._bundle_ctx.project_root,
181
+ deploy_root=self._bundle_ctx.deploy_root,
186
182
  )
187
183
  bundle_map.add(artifact_to_process)
188
184
 
@@ -230,13 +226,9 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
230
226
  edit_setup_script_with_exec_imm_sql(
231
227
  collected_sql_files=collected_sql_files,
232
228
  deploy_root=bundle_map.deploy_root(),
233
- generated_root=self._generated_root,
229
+ generated_root=self._bundle_ctx.generated_root,
234
230
  )
235
231
 
236
- @property
237
- def _generated_root(self):
238
- return self._na_project.generated_root / "snowpark"
239
-
240
232
  def _normalize_imports(
241
233
  self,
242
234
  extension_fn: NativeAppExtensionFunction,
@@ -315,7 +307,7 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
315
307
  self, bundle_map: BundleMap, processor_mapping: Optional[ProcessorMapping]
316
308
  ) -> Dict[Path, List[NativeAppExtensionFunction]]:
317
309
  kwargs = (
318
- _determine_virtual_env(self._na_project.project_root, processor_mapping)
310
+ _determine_virtual_env(self._bundle_ctx.project_root, processor_mapping)
319
311
  if processor_mapping is not None
320
312
  else {}
321
313
  )
@@ -338,7 +330,7 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
338
330
  )
339
331
  collected_extension_function_json = _execute_in_sandbox(
340
332
  py_file=str(dest_file.resolve()),
341
- deploy_root=self._na_project.deploy_root,
333
+ deploy_root=self._bundle_ctx.deploy_root,
342
334
  kwargs=kwargs,
343
335
  )
344
336
 
@@ -369,8 +361,10 @@ class SnowparkAnnotationProcessor(ArtifactProcessor):
369
361
  """
370
362
  Generates a SQL filename for the generated root from the python file, and creates its parent directories.
371
363
  """
372
- relative_py_file = py_file.relative_to(self._na_project.deploy_root)
373
- sql_file = Path(self._generated_root, relative_py_file.with_suffix(".sql"))
364
+ relative_py_file = py_file.relative_to(self._bundle_ctx.deploy_root)
365
+ sql_file = Path(
366
+ self._bundle_ctx.generated_root, relative_py_file.with_suffix(".sql")
367
+ )
374
368
  if sql_file.exists():
375
369
  cc.warning(
376
370
  f"""\
@@ -0,0 +1,93 @@
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
+ from typing import Optional
18
+
19
+ import jinja2
20
+ from snowflake.cli._plugins.nativeapp.artifacts import BundleMap
21
+ from snowflake.cli._plugins.nativeapp.codegen.artifact_processor import (
22
+ ArtifactProcessor,
23
+ )
24
+ from snowflake.cli._plugins.nativeapp.exceptions import InvalidTemplateInFileError
25
+ from snowflake.cli.api.cli_global_context import get_cli_context
26
+ from snowflake.cli.api.console import cli_console as cc
27
+ from snowflake.cli.api.project.schemas.native_app.path_mapping import (
28
+ PathMapping,
29
+ ProcessorMapping,
30
+ )
31
+ from snowflake.cli.api.rendering.project_definition_templates import (
32
+ get_client_side_jinja_env,
33
+ )
34
+ from snowflake.cli.api.rendering.sql_templates import (
35
+ choose_sql_jinja_env_based_on_template_syntax,
36
+ )
37
+
38
+
39
+ class TemplatesProcessor(ArtifactProcessor):
40
+ """
41
+ Processor class to perform template expansion on all relevant artifacts (specified in the project definition file).
42
+ """
43
+
44
+ def process(
45
+ self,
46
+ artifact_to_process: PathMapping,
47
+ processor_mapping: Optional[ProcessorMapping],
48
+ **kwargs,
49
+ ):
50
+ """
51
+ Process the artifact by executing the template expansion logic on it.
52
+ """
53
+ cc.step(f"Processing artifact {artifact_to_process} with templates processor")
54
+
55
+ bundle_map = BundleMap(
56
+ project_root=self._bundle_ctx.project_root,
57
+ deploy_root=self._bundle_ctx.deploy_root,
58
+ )
59
+ bundle_map.add(artifact_to_process)
60
+
61
+ for src, dest in bundle_map.all_mappings(
62
+ absolute=True,
63
+ expand_directories=True,
64
+ ):
65
+ if src.is_dir():
66
+ continue
67
+ with self.edit_file(dest) as f:
68
+ file_name = src.relative_to(self._bundle_ctx.project_root)
69
+
70
+ jinja_env = (
71
+ choose_sql_jinja_env_based_on_template_syntax(
72
+ f.contents, reference_name=file_name
73
+ )
74
+ if dest.name.lower().endswith(".sql")
75
+ else get_client_side_jinja_env()
76
+ )
77
+
78
+ try:
79
+ expanded_template = jinja_env.from_string(f.contents).render(
80
+ get_cli_context().template_context
81
+ )
82
+
83
+ # For now, we are printing the source file path in the error message
84
+ # instead of the destination file path to make it easier for the user
85
+ # to identify the file that has the error, and edit the correct file.
86
+ except jinja2.TemplateSyntaxError as e:
87
+ raise InvalidTemplateInFileError(file_name, e, e.lineno) from e
88
+
89
+ except jinja2.UndefinedError as e:
90
+ raise InvalidTemplateInFileError(file_name, e) from e
91
+
92
+ if expanded_template != f.contents:
93
+ f.edited_contents = expanded_template