snowflake-cli-labs 2.8.0rc1__py3-none-any.whl → 3.0.0__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 (251) 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 +22 -13
  4. snowflake/cli/{app → _app}/commands_registration/builtin_plugins.py +15 -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/secret.py +9 -0
  16. snowflake/cli/{app → _app}/snow_connector.py +127 -61
  17. snowflake/cli/{app → _app}/telemetry.py +38 -7
  18. snowflake/cli/_app/version_check.py +74 -0
  19. snowflake/cli/{plugins → _plugins}/connection/commands.py +34 -11
  20. snowflake/cli/_plugins/connection/plugin_spec.py +30 -0
  21. snowflake/cli/{plugins → _plugins}/connection/util.py +16 -0
  22. snowflake/cli/{plugins → _plugins}/cortex/commands.py +54 -49
  23. snowflake/cli/{plugins → _plugins}/cortex/constants.py +1 -1
  24. snowflake/cli/{plugins → _plugins}/cortex/manager.py +5 -5
  25. snowflake/cli/{plugins → _plugins}/cortex/plugin_spec.py +1 -1
  26. snowflake/cli/{plugins → _plugins}/git/commands.py +79 -26
  27. snowflake/cli/{plugins → _plugins}/git/manager.py +72 -17
  28. snowflake/cli/{plugins → _plugins}/git/plugin_spec.py +1 -1
  29. snowflake/cli/_plugins/helpers/commands.py +90 -0
  30. snowflake/cli/{plugins/notebook → _plugins/helpers}/plugin_spec.py +1 -1
  31. snowflake/cli/{plugins → _plugins}/init/commands.py +10 -6
  32. snowflake/cli/{plugins → _plugins}/init/plugin_spec.py +1 -1
  33. snowflake/cli/{plugins → _plugins}/nativeapp/artifacts.py +24 -9
  34. snowflake/cli/_plugins/nativeapp/bundle_context.py +31 -0
  35. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/artifact_processor.py +4 -4
  36. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/compiler.py +37 -18
  37. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +249 -0
  38. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/setup/setup_driver.py.source +5 -2
  39. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/extension_function_utils.py +5 -5
  40. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/models.py +1 -1
  41. snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/python_processor.py +29 -34
  42. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +114 -0
  43. snowflake/cli/{plugins → _plugins}/nativeapp/commands.py +252 -132
  44. snowflake/cli/{plugins → _plugins}/nativeapp/common_flags.py +1 -1
  45. snowflake/cli/_plugins/nativeapp/entities/application.py +878 -0
  46. snowflake/cli/_plugins/nativeapp/entities/application_package.py +1392 -0
  47. snowflake/cli/{plugins → _plugins}/nativeapp/exceptions.py +3 -12
  48. snowflake/cli/_plugins/nativeapp/manager.py +415 -0
  49. snowflake/cli/{plugins/connection → _plugins/nativeapp}/plugin_spec.py +1 -1
  50. snowflake/cli/{plugins → _plugins}/nativeapp/policy.py +3 -0
  51. snowflake/cli/{plugins → _plugins}/nativeapp/project_model.py +36 -20
  52. snowflake/cli/_plugins/nativeapp/run_processor.py +184 -0
  53. snowflake/cli/_plugins/nativeapp/same_account_install_method.py +70 -0
  54. snowflake/cli/_plugins/nativeapp/teardown_processor.py +70 -0
  55. snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +262 -0
  56. snowflake/cli/{plugins → _plugins}/nativeapp/version/commands.py +20 -49
  57. snowflake/cli/_plugins/nativeapp/version/version_processor.py +98 -0
  58. snowflake/cli/{plugins → _plugins}/notebook/commands.py +8 -6
  59. snowflake/cli/{plugins → _plugins}/notebook/manager.py +14 -14
  60. snowflake/cli/{plugins/nativeapp → _plugins/notebook}/plugin_spec.py +1 -1
  61. snowflake/cli/{plugins → _plugins}/notebook/types.py +0 -1
  62. snowflake/cli/{plugins → _plugins}/object/command_aliases.py +6 -5
  63. snowflake/cli/{plugins → _plugins}/object/commands.py +16 -10
  64. snowflake/cli/{plugins → _plugins}/object/manager.py +43 -21
  65. snowflake/cli/{plugins → _plugins}/object/plugin_spec.py +1 -1
  66. snowflake/cli/_plugins/snowpark/commands.py +450 -0
  67. snowflake/cli/_plugins/snowpark/common.py +268 -0
  68. snowflake/cli/{plugins → _plugins}/snowpark/models.py +2 -8
  69. snowflake/cli/{plugins → _plugins}/snowpark/package/anaconda_packages.py +2 -36
  70. snowflake/cli/{plugins → _plugins}/snowpark/package/commands.py +13 -74
  71. snowflake/cli/{plugins → _plugins}/snowpark/package/manager.py +4 -3
  72. snowflake/cli/{plugins → _plugins}/snowpark/package_utils.py +5 -5
  73. snowflake/cli/_plugins/snowpark/plugin_spec.py +30 -0
  74. snowflake/cli/_plugins/snowpark/snowpark_entity.py +29 -0
  75. snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +173 -0
  76. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +109 -0
  77. snowflake/cli/{plugins → _plugins}/snowpark/snowpark_shared.py +0 -36
  78. snowflake/cli/{plugins → _plugins}/snowpark/zipper.py +16 -8
  79. snowflake/cli/{plugins → _plugins}/spcs/__init__.py +5 -7
  80. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/commands.py +29 -28
  81. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/manager.py +3 -3
  82. snowflake/cli/{plugins → _plugins}/spcs/image_registry/commands.py +3 -3
  83. snowflake/cli/{plugins → _plugins}/spcs/image_repository/commands.py +25 -19
  84. snowflake/cli/{plugins → _plugins}/spcs/image_repository/manager.py +1 -1
  85. snowflake/cli/{plugins → _plugins}/spcs/plugin_spec.py +1 -1
  86. snowflake/cli/{plugins → _plugins}/spcs/services/commands.py +66 -32
  87. snowflake/cli/{plugins → _plugins}/spcs/services/manager.py +43 -5
  88. snowflake/cli/{plugins → _plugins}/sql/commands.py +20 -17
  89. snowflake/cli/{plugins → _plugins}/sql/manager.py +1 -1
  90. snowflake/cli/{plugins → _plugins}/sql/plugin_spec.py +1 -1
  91. snowflake/cli/{plugins → _plugins}/stage/commands.py +20 -17
  92. snowflake/cli/{plugins → _plugins}/stage/diff.py +1 -47
  93. snowflake/cli/{plugins → _plugins}/stage/manager.py +62 -24
  94. snowflake/cli/{plugins → _plugins}/stage/plugin_spec.py +1 -1
  95. snowflake/cli/_plugins/stage/utils.py +54 -0
  96. snowflake/cli/{plugins → _plugins}/streamlit/commands.py +71 -62
  97. snowflake/cli/{plugins → _plugins}/streamlit/manager.py +68 -70
  98. snowflake/cli/_plugins/streamlit/plugin_spec.py +30 -0
  99. snowflake/cli/_plugins/streamlit/streamlit_entity.py +12 -0
  100. snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +66 -0
  101. snowflake/cli/_plugins/workspace/action_context.py +18 -0
  102. snowflake/cli/_plugins/workspace/commands.py +306 -0
  103. snowflake/cli/_plugins/workspace/manager.py +74 -0
  104. snowflake/cli/_plugins/workspace/plugin_spec.py +30 -0
  105. snowflake/cli/api/cli_global_context.py +152 -295
  106. snowflake/cli/api/commands/common.py +25 -0
  107. snowflake/cli/api/commands/decorators.py +19 -4
  108. snowflake/cli/api/commands/experimental_behaviour.py +2 -3
  109. snowflake/cli/api/commands/flags.py +143 -222
  110. snowflake/cli/api/commands/overrideable_parameter.py +143 -0
  111. snowflake/cli/api/commands/snow_typer.py +21 -11
  112. snowflake/cli/api/commands/utils.py +18 -0
  113. snowflake/cli/api/config.py +44 -12
  114. snowflake/cli/api/connections.py +216 -0
  115. snowflake/cli/api/console/abc.py +8 -3
  116. snowflake/cli/api/constants.py +11 -0
  117. snowflake/cli/api/entities/common.py +56 -0
  118. snowflake/cli/api/entities/utils.py +370 -0
  119. snowflake/cli/api/errno.py +1 -0
  120. snowflake/cli/api/exceptions.py +31 -5
  121. snowflake/cli/api/feature_flags.py +0 -1
  122. snowflake/cli/api/identifiers.py +45 -9
  123. snowflake/cli/api/metrics.py +92 -0
  124. snowflake/cli/api/project/definition.py +48 -6
  125. snowflake/cli/api/project/definition_conversion.py +400 -0
  126. snowflake/cli/api/project/definition_manager.py +16 -5
  127. snowflake/cli/api/project/project_verification.py +3 -3
  128. snowflake/cli/api/project/schemas/entities/common.py +91 -16
  129. snowflake/cli/api/project/schemas/entities/entities.py +37 -6
  130. snowflake/cli/api/project/schemas/project_definition.py +180 -49
  131. snowflake/cli/api/project/schemas/updatable_model.py +11 -3
  132. snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
  133. snowflake/cli/api/project/schemas/{identifier_model.py → v1/identifier_model.py} +3 -1
  134. snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
  135. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/application.py +8 -9
  136. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/native_app.py +4 -4
  137. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/package.py +7 -1
  138. snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
  139. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/callable.py +2 -2
  140. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/snowpark.py +2 -2
  141. snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
  142. snowflake/cli/api/project/schemas/{streamlit → v1/streamlit}/streamlit.py +2 -1
  143. snowflake/cli/api/project/util.py +23 -6
  144. snowflake/cli/api/rendering/jinja.py +14 -8
  145. snowflake/cli/api/rendering/project_definition_templates.py +5 -1
  146. snowflake/cli/api/rendering/sql_templates.py +56 -11
  147. snowflake/cli/api/rest_api.py +11 -5
  148. snowflake/cli/api/secure_path.py +16 -18
  149. snowflake/cli/api/secure_utils.py +90 -1
  150. snowflake/cli/api/sql_execution.py +47 -27
  151. snowflake/cli/api/utils/definition_rendering.py +45 -13
  152. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/METADATA +20 -18
  153. snowflake_cli_labs-3.0.0.dist-info/RECORD +242 -0
  154. snowflake_cli_labs-3.0.0.dist-info/entry_points.txt +2 -0
  155. snowflake/cli/api/commands/project_initialisation.py +0 -65
  156. snowflake/cli/api/commands/typer_pre_execute.py +0 -26
  157. snowflake/cli/api/project/schemas/entities/application_entity.py +0 -44
  158. snowflake/cli/api/project/schemas/entities/application_package_entity.py +0 -66
  159. snowflake/cli/app/build_and_push.sh +0 -8
  160. snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -172
  161. snowflake/cli/plugins/nativeapp/init.py +0 -345
  162. snowflake/cli/plugins/nativeapp/manager.py +0 -823
  163. snowflake/cli/plugins/nativeapp/run_processor.py +0 -389
  164. snowflake/cli/plugins/nativeapp/teardown_processor.py +0 -301
  165. snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +0 -135
  166. snowflake/cli/plugins/nativeapp/version/version_processor.py +0 -362
  167. snowflake/cli/plugins/object_stage_deprecated/__init__.py +0 -15
  168. snowflake/cli/plugins/object_stage_deprecated/commands.py +0 -122
  169. snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +0 -32
  170. snowflake/cli/plugins/snowpark/commands.py +0 -548
  171. snowflake/cli/plugins/snowpark/common.py +0 -307
  172. snowflake/cli/plugins/snowpark/manager.py +0 -109
  173. snowflake/cli/plugins/snowpark/plugin_spec.py +0 -30
  174. snowflake/cli/plugins/snowpark/snowpark_package_paths.py +0 -65
  175. snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
  176. snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
  177. snowflake/cli/plugins/streamlit/__init__.py +0 -13
  178. snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
  179. snowflake/cli/plugins/workspace/__init__.py +0 -13
  180. snowflake/cli/plugins/workspace/commands.py +0 -35
  181. snowflake/cli/plugins/workspace/plugin_spec.py +0 -30
  182. snowflake/cli/templates/default_snowpark/.gitignore +0 -4
  183. snowflake/cli/templates/default_snowpark/app/common.py +0 -2
  184. snowflake/cli/templates/default_snowpark/app/functions.py +0 -15
  185. snowflake/cli/templates/default_snowpark/app/procedures.py +0 -22
  186. snowflake/cli/templates/default_snowpark/requirements.txt +0 -1
  187. snowflake/cli/templates/default_snowpark/snowflake.yml +0 -23
  188. snowflake/cli/templates/default_streamlit/.gitignore +0 -4
  189. snowflake/cli/templates/default_streamlit/common/hello.py +0 -2
  190. snowflake/cli/templates/default_streamlit/environment.yml +0 -6
  191. snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -3
  192. snowflake/cli/templates/default_streamlit/snowflake.yml +0 -10
  193. snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -4
  194. snowflake_cli_labs-2.8.0rc1.dist-info/RECORD +0 -240
  195. snowflake_cli_labs-2.8.0rc1.dist-info/entry_points.txt +0 -2
  196. /snowflake/cli/{app → _app}/__init__.py +0 -0
  197. /snowflake/cli/{api/project/schemas/native_app → _app/api_impl}/__init__.py +0 -0
  198. /snowflake/cli/{api/project/schemas/snowpark → _app/api_impl/plugin}/__init__.py +0 -0
  199. /snowflake/cli/{app → _app}/api_impl/plugin/plugin_config_provider_impl.py +0 -0
  200. /snowflake/cli/{app → _app}/commands_registration/__init__.py +0 -0
  201. /snowflake/cli/{app → _app}/commands_registration/threadsafe.py +0 -0
  202. /snowflake/cli/{app → _app}/constants.py +0 -0
  203. /snowflake/cli/{api/project/schemas/streamlit → _app/dev}/__init__.py +0 -0
  204. /snowflake/cli/{app → _app}/dev/commands_structure.py +0 -0
  205. /snowflake/cli/{app/api_impl → _app/dev/docs}/__init__.py +0 -0
  206. /snowflake/cli/{app → _app}/dev/docs/project_definition_generate_json_schema.py +0 -0
  207. /snowflake/cli/{app → _app}/dev/docs/template_utils.py +0 -0
  208. /snowflake/cli/{app → _app}/dev/docs/templates/definition_description.rst.jinja2 +0 -0
  209. /snowflake/cli/{app → _app}/dev/docs/templates/overview.rst.jinja2 +0 -0
  210. /snowflake/cli/{app → _app}/dev/pycharm_remote_debug.py +0 -0
  211. /snowflake/cli/{app → _app}/loggers.py +0 -0
  212. /snowflake/cli/{app/api_impl/plugin → _plugins}/__init__.py +0 -0
  213. /snowflake/cli/{app/dev → _plugins/connection}/__init__.py +0 -0
  214. /snowflake/cli/{app/dev/docs → _plugins/cortex}/__init__.py +0 -0
  215. /snowflake/cli/{plugins → _plugins}/cortex/types.py +0 -0
  216. /snowflake/cli/{plugins → _plugins/git}/__init__.py +0 -0
  217. /snowflake/cli/{plugins/connection → _plugins/helpers}/__init__.py +0 -0
  218. /snowflake/cli/{plugins/cortex → _plugins/init}/__init__.py +0 -0
  219. /snowflake/cli/{plugins/git → _plugins/nativeapp}/__init__.py +0 -0
  220. /snowflake/cli/{plugins/init → _plugins/nativeapp/codegen}/__init__.py +0 -0
  221. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/sandbox.py +0 -0
  222. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -0
  223. /snowflake/cli/{plugins → _plugins}/nativeapp/constants.py +0 -0
  224. /snowflake/cli/{templates/default_snowpark/app → _plugins/nativeapp/entities}/__init__.py +0 -0
  225. /snowflake/cli/{plugins → _plugins}/nativeapp/feature_flags.py +0 -0
  226. /snowflake/cli/{plugins → _plugins}/nativeapp/utils.py +0 -0
  227. /snowflake/cli/{plugins/nativeapp → _plugins/nativeapp/version}/__init__.py +0 -0
  228. /snowflake/cli/{plugins/nativeapp/codegen → _plugins/notebook}/__init__.py +0 -0
  229. /snowflake/cli/{plugins → _plugins}/notebook/exceptions.py +0 -0
  230. /snowflake/cli/{plugins/nativeapp/version → _plugins/object}/__init__.py +0 -0
  231. /snowflake/cli/{plugins → _plugins}/object/common.py +0 -0
  232. /snowflake/cli/{plugins/notebook → _plugins/snowpark}/__init__.py +0 -0
  233. /snowflake/cli/{plugins/object → _plugins/snowpark/package}/__init__.py +0 -0
  234. /snowflake/cli/{plugins → _plugins}/snowpark/package/utils.py +0 -0
  235. /snowflake/cli/{plugins → _plugins}/spcs/common.py +0 -0
  236. /snowflake/cli/{plugins/snowpark → _plugins/spcs/compute_pool}/__init__.py +0 -0
  237. /snowflake/cli/{plugins/snowpark/package → _plugins/spcs/image_registry}/__init__.py +0 -0
  238. /snowflake/cli/{plugins → _plugins}/spcs/image_registry/manager.py +0 -0
  239. /snowflake/cli/{plugins/spcs/compute_pool → _plugins/spcs/image_repository}/__init__.py +0 -0
  240. /snowflake/cli/{plugins/spcs/image_registry → _plugins/spcs/services}/__init__.py +0 -0
  241. /snowflake/cli/{plugins/spcs/image_repository → _plugins/sql}/__init__.py +0 -0
  242. /snowflake/cli/{plugins → _plugins}/sql/snowsql_templating.py +0 -0
  243. /snowflake/cli/{plugins/spcs/jobs → _plugins/stage}/__init__.py +0 -0
  244. /snowflake/cli/{plugins → _plugins}/stage/md5.py +0 -0
  245. /snowflake/cli/{plugins/spcs/services → _plugins/streamlit}/__init__.py +0 -0
  246. /snowflake/cli/{plugins/sql → _plugins/workspace}/__init__.py +0 -0
  247. /snowflake/cli/{plugins/stage → api/project/schemas/entities}/__init__.py +0 -0
  248. /snowflake/cli/api/project/schemas/{native_app → v1/native_app}/path_mapping.py +0 -0
  249. /snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/argument.py +0 -0
  250. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/WHEEL +0 -0
  251. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,92 @@
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 typing import Dict, Optional
16
+
17
+
18
+ class _TypePrefix:
19
+ FEATURES = "features"
20
+
21
+
22
+ class _DomainPrefix:
23
+ GLOBAL = "global"
24
+ APP = "app"
25
+ SQL = "sql"
26
+
27
+
28
+ class CLICounterField:
29
+ """
30
+ for each counter field we're adopting a convention of
31
+ <type>.<domain>.<name>
32
+ for example, if we're tracking a global feature, then the field name would be
33
+ features.global.feature_name
34
+
35
+ The metrics API is implemented to be generic, but we are adopting a convention
36
+ for feature tracking with the following model for a given command execution:
37
+ * counter not present -> feature is not available
38
+ * counter == 0 -> feature is available, but not used
39
+ * counter == 1 -> feature is used
40
+ this makes it easy to compute percentages for feature dashboards in Snowsight
41
+ """
42
+
43
+ TEMPLATES_PROCESSOR = (
44
+ f"{_TypePrefix.FEATURES}.{_DomainPrefix.GLOBAL}.templates_processor"
45
+ )
46
+ SQL_TEMPLATES = f"{_TypePrefix.FEATURES}.{_DomainPrefix.SQL}.sql_templates"
47
+ PDF_TEMPLATES = f"{_TypePrefix.FEATURES}.{_DomainPrefix.GLOBAL}.pdf_templates"
48
+ SNOWPARK_PROCESSOR = (
49
+ f"{_TypePrefix.FEATURES}.{_DomainPrefix.APP}.snowpark_processor"
50
+ )
51
+ POST_DEPLOY_SCRIPTS = (
52
+ f"{_TypePrefix.FEATURES}.{_DomainPrefix.APP}.post_deploy_scripts"
53
+ )
54
+ PACKAGE_SCRIPTS = f"{_TypePrefix.FEATURES}.{_DomainPrefix.APP}.package_scripts"
55
+
56
+
57
+ class CLIMetrics:
58
+ """
59
+ Class to track various metrics across the execution of a command
60
+ """
61
+
62
+ def __init__(self):
63
+ self._counters: Dict[str, int] = {}
64
+
65
+ def __eq__(self, other):
66
+ if isinstance(other, CLIMetrics):
67
+ return self._counters == other._counters
68
+ return False
69
+
70
+ def get_counter(self, name: str) -> Optional[int]:
71
+ return self._counters.get(name)
72
+
73
+ def set_counter(self, name: str, value: int) -> None:
74
+ self._counters[name] = value
75
+
76
+ def set_counter_default(self, name: str, value: int) -> None:
77
+ """
78
+ sets the counter if it does not already exist
79
+ """
80
+ if name not in self._counters:
81
+ self.set_counter(name, value)
82
+
83
+ def increment_counter(self, name: str, value: int = 1) -> None:
84
+ if name not in self._counters:
85
+ self.set_counter(name, value)
86
+ else:
87
+ self._counters[name] += value
88
+
89
+ @property
90
+ def counters(self) -> Dict[str, int]:
91
+ # return a copy of the original dict to avoid mutating the original
92
+ return self._counters.copy()
@@ -18,10 +18,12 @@ from pathlib import Path
18
18
  from typing import List, Optional
19
19
 
20
20
  import yaml
21
- from snowflake.cli.api.cli_global_context import cli_context
21
+ from click import ClickException
22
+ from snowflake.cli.api.cli_global_context import get_cli_context
22
23
  from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB
23
24
  from snowflake.cli.api.project.schemas.project_definition import (
24
25
  ProjectProperties,
26
+ YamlOverride,
25
27
  )
26
28
  from snowflake.cli.api.project.util import (
27
29
  append_to_identifier,
@@ -30,9 +32,13 @@ from snowflake.cli.api.project.util import (
30
32
  to_identifier,
31
33
  )
32
34
  from snowflake.cli.api.secure_path import SecurePath
33
- from snowflake.cli.api.utils.definition_rendering import render_definition_template
35
+ from snowflake.cli.api.utils.definition_rendering import (
36
+ raw_project_properties,
37
+ render_definition_template,
38
+ )
34
39
  from snowflake.cli.api.utils.dict_utils import deep_merge_dicts
35
40
  from snowflake.cli.api.utils.types import Context, Definition
41
+ from yaml import MappingNode, SequenceNode
36
42
 
37
43
  DEFAULT_USERNAME = "unknown_user"
38
44
 
@@ -42,8 +48,14 @@ def _get_merged_definitions(paths: List[Path]) -> Optional[Definition]:
42
48
  if len(spaths) == 0:
43
49
  return None
44
50
 
51
+ loader = yaml.BaseLoader
52
+ loader.add_constructor(
53
+ yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, _no_duplicates_constructor
54
+ )
55
+ loader.add_constructor("!override", _override_tag)
56
+
45
57
  with spaths[0].open("r", read_file_limit_mb=DEFAULT_SIZE_LIMIT_MB) as base_yml:
46
- definition = yaml.load(base_yml.read(), Loader=yaml.loader.BaseLoader) or {}
58
+ definition = yaml.load(base_yml.read(), Loader=loader) or {}
47
59
 
48
60
  for override_path in spaths[1:]:
49
61
  with override_path.open(
@@ -58,7 +70,9 @@ def _get_merged_definitions(paths: List[Path]) -> Optional[Definition]:
58
70
 
59
71
 
60
72
  def load_project(
61
- paths: List[Path], context_overrides: Optional[Context] = None
73
+ paths: List[Path],
74
+ context_overrides: Optional[Context] = None,
75
+ render_templates: bool = True,
62
76
  ) -> ProjectProperties:
63
77
  """
64
78
  Loads project definition, optionally overriding values. Definition values
@@ -66,7 +80,10 @@ def load_project(
66
80
  Templating is also applied after the merging process.
67
81
  """
68
82
  merged_definitions = _get_merged_definitions(paths)
69
- return render_definition_template(merged_definitions, context_overrides or {})
83
+ if render_templates:
84
+ return render_definition_template(merged_definitions, context_overrides or {})
85
+ else:
86
+ return raw_project_properties(merged_definitions)
70
87
 
71
88
 
72
89
  def default_app_package(project_name: str):
@@ -75,10 +92,35 @@ def default_app_package(project_name: str):
75
92
 
76
93
 
77
94
  def default_role():
78
- conn = cli_context.connection
95
+ conn = get_cli_context().connection
79
96
  return conn.role
80
97
 
81
98
 
82
99
  def default_application(project_name: str):
83
100
  user = sanitize_identifier(get_env_username() or DEFAULT_USERNAME).lower()
84
101
  return append_to_identifier(to_identifier(project_name), f"_{user}")
102
+
103
+
104
+ def _no_duplicates_constructor(loader, node, deep=False):
105
+ """
106
+ Raises error it there are duplicated keys on the same level in the yaml file
107
+ """
108
+ mapping = {}
109
+
110
+ for key_node, value_node in node.value:
111
+ key = loader.construct_object(key_node, deep=deep)
112
+ value = loader.construct_object(value_node, deep=deep)
113
+ if key in mapping.keys():
114
+ raise ClickException(
115
+ f"While loading the project definition file, duplicate key was found: {key}"
116
+ )
117
+ mapping[key] = value
118
+ return loader.construct_mapping(node, deep)
119
+
120
+
121
+ def _override_tag(loader, node, deep=False):
122
+ if isinstance(node, SequenceNode):
123
+ return YamlOverride(data=loader.construct_sequence(node, deep))
124
+ if isinstance(node, MappingNode):
125
+ return YamlOverride(data=loader.construct_mapping(node, deep))
126
+ return node.value
@@ -0,0 +1,400 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from pathlib import Path
5
+ from typing import Any, Dict, Literal, Optional
6
+
7
+ from click import ClickException
8
+ from snowflake.cli._plugins.nativeapp.artifacts import (
9
+ BundleMap,
10
+ )
11
+ from snowflake.cli._plugins.snowpark.common import is_name_a_templated_one
12
+ from snowflake.cli.api.constants import (
13
+ DEFAULT_ENV_FILE,
14
+ DEFAULT_PAGES_DIR,
15
+ PROJECT_TEMPLATE_VARIABLE_CLOSING,
16
+ PROJECT_TEMPLATE_VARIABLE_OPENING,
17
+ SNOWPARK_SHARED_MIXIN,
18
+ )
19
+ from snowflake.cli.api.entities.utils import render_script_template
20
+ from snowflake.cli.api.project.schemas.entities.common import (
21
+ SqlScriptHookType,
22
+ )
23
+ from snowflake.cli.api.project.schemas.project_definition import (
24
+ ProjectDefinition,
25
+ ProjectDefinitionV2,
26
+ )
27
+ from snowflake.cli.api.project.schemas.v1.native_app.application import (
28
+ Application,
29
+ ApplicationV11,
30
+ )
31
+ from snowflake.cli.api.project.schemas.v1.native_app.native_app import NativeApp
32
+ from snowflake.cli.api.project.schemas.v1.native_app.package import Package, PackageV11
33
+ from snowflake.cli.api.project.schemas.v1.snowpark.callable import (
34
+ FunctionSchema,
35
+ ProcedureSchema,
36
+ )
37
+ from snowflake.cli.api.project.schemas.v1.snowpark.snowpark import Snowpark
38
+ from snowflake.cli.api.project.schemas.v1.streamlit.streamlit import Streamlit
39
+ from snowflake.cli.api.rendering.jinja import get_basic_jinja_env
40
+
41
+ log = logging.getLogger(__name__)
42
+
43
+
44
+ def _is_field_defined(template_context: Optional[Dict[str, Any]], *path: str) -> bool:
45
+ """
46
+ Determines if a field is defined in the provided template context. For example,
47
+
48
+ _is_field_defined({"ctx": {"native_app": {"bundle_root": "my_root"}}}, "ctx", "native_app", "bundle_root")
49
+
50
+ returns True. If the provided template context is None, this function returns True for all paths.
51
+
52
+ """
53
+ if template_context is None:
54
+ return True # No context, so assume that all variables are defined
55
+
56
+ current_dict = template_context
57
+ for key in path:
58
+ if not isinstance(current_dict, dict):
59
+ return False
60
+ if key not in current_dict:
61
+ return False
62
+ current_dict = current_dict[key]
63
+
64
+ return True
65
+
66
+
67
+ def convert_project_definition_to_v2(
68
+ project_root: Path,
69
+ pd: ProjectDefinition,
70
+ accept_templates: bool = False,
71
+ template_context: Optional[Dict[str, Any]] = None,
72
+ ) -> ProjectDefinitionV2:
73
+ _check_if_project_definition_meets_requirements(pd, accept_templates)
74
+
75
+ snowpark_data = convert_snowpark_to_v2_data(pd.snowpark) if pd.snowpark else {}
76
+ streamlit_data = convert_streamlit_to_v2_data(pd.streamlit) if pd.streamlit else {}
77
+ native_app_data = (
78
+ convert_native_app_to_v2_data(project_root, pd.native_app, template_context)
79
+ if pd.native_app
80
+ else {}
81
+ )
82
+ envs = convert_envs_to_v2(pd)
83
+
84
+ data = {
85
+ "definition_version": "2",
86
+ "entities": get_list_of_all_entities(
87
+ snowpark_data.get("entities", {}),
88
+ streamlit_data.get("entities", {}),
89
+ native_app_data.get("entities", {}),
90
+ ),
91
+ "mixins": snowpark_data.get("mixins", None),
92
+ "env": envs,
93
+ }
94
+
95
+ return ProjectDefinitionV2(**data)
96
+
97
+
98
+ def convert_snowpark_to_v2_data(snowpark: Snowpark) -> Dict[str, Any]:
99
+ artifact_mapping = {"src": snowpark.src}
100
+ if snowpark.project_name:
101
+ artifact_mapping["dest"] = snowpark.project_name
102
+
103
+ data: dict = {
104
+ "mixins": {
105
+ SNOWPARK_SHARED_MIXIN: {
106
+ "stage": snowpark.stage_name,
107
+ "artifacts": [artifact_mapping],
108
+ }
109
+ },
110
+ "entities": {},
111
+ }
112
+
113
+ for index, entity in enumerate([*snowpark.procedures, *snowpark.functions]):
114
+ identifier = {"name": entity.name}
115
+ if entity.database is not None:
116
+ identifier["database"] = entity.database
117
+ if entity.schema_name is not None:
118
+ identifier["schema"] = entity.schema_name
119
+
120
+ entity_name = (
121
+ f"snowpark_entity_{index}"
122
+ if is_name_a_templated_one(entity.name)
123
+ else entity.name
124
+ )
125
+
126
+ if entity_name in data["entities"]:
127
+ raise ClickException(
128
+ f"Entity with name {entity_name} seems to be duplicated. Please rename it and try again."
129
+ )
130
+
131
+ v2_entity = {
132
+ "type": "function" if isinstance(entity, FunctionSchema) else "procedure",
133
+ "stage": snowpark.stage_name,
134
+ "handler": entity.handler,
135
+ "returns": entity.returns,
136
+ "signature": entity.signature,
137
+ "runtime": entity.runtime,
138
+ "external_access_integrations": entity.external_access_integrations,
139
+ "secrets": entity.secrets,
140
+ "imports": entity.imports,
141
+ "identifier": identifier,
142
+ "meta": {"use_mixins": [SNOWPARK_SHARED_MIXIN]},
143
+ }
144
+ if isinstance(entity, ProcedureSchema):
145
+ v2_entity["execute_as_caller"] = entity.execute_as_caller
146
+
147
+ data["entities"][entity_name] = v2_entity
148
+
149
+ return data
150
+
151
+
152
+ def convert_streamlit_to_v2_data(streamlit: Streamlit) -> Dict[str, Any]:
153
+ # Process env file and pages dir
154
+ environment_file = _process_streamlit_files(streamlit.env_file, "environment")
155
+ pages_dir = _process_streamlit_files(streamlit.pages_dir, "pages")
156
+
157
+ # Build V2 definition
158
+ artifacts = [
159
+ streamlit.main_file,
160
+ environment_file,
161
+ pages_dir,
162
+ ]
163
+ artifacts = [a for a in artifacts if a is not None]
164
+
165
+ if streamlit.additional_source_files:
166
+ artifacts.extend(streamlit.additional_source_files)
167
+
168
+ identifier = {"name": streamlit.name}
169
+ if streamlit.schema_name:
170
+ identifier["schema"] = streamlit.schema_name
171
+ if streamlit.database:
172
+ identifier["database"] = streamlit.database
173
+
174
+ streamlit_name = (
175
+ "streamlit_entity_1"
176
+ if is_name_a_templated_one(streamlit.name)
177
+ else streamlit.name
178
+ )
179
+
180
+ data = {
181
+ "entities": {
182
+ streamlit_name: {
183
+ "type": "streamlit",
184
+ "identifier": identifier,
185
+ "title": streamlit.title,
186
+ "comment": streamlit.comment,
187
+ "query_warehouse": streamlit.query_warehouse,
188
+ "main_file": str(streamlit.main_file),
189
+ "pages_dir": str(streamlit.pages_dir),
190
+ "stage": streamlit.stage,
191
+ "artifacts": artifacts,
192
+ }
193
+ }
194
+ }
195
+ return data
196
+
197
+
198
+ def convert_native_app_to_v2_data(
199
+ project_root,
200
+ native_app: NativeApp,
201
+ template_context: Optional[Dict[str, Any]] = None,
202
+ ) -> Dict[str, Any]:
203
+ def _make_meta(obj: Application | Package):
204
+ meta = {}
205
+ if obj.role:
206
+ meta["role"] = obj.role
207
+ if obj.warehouse:
208
+ meta["warehouse"] = obj.warehouse
209
+ if obj.post_deploy:
210
+ meta["post_deploy"] = obj.post_deploy
211
+ return meta
212
+
213
+ def _find_manifest():
214
+ # We don't know which file in the project directory is the actual manifest,
215
+ # and we can't iterate through the artifacts property since the src can contain
216
+ # glob patterns. The simplest solution is to bundle the app and find the
217
+ # manifest file from the resultant BundleMap, since the bundle process ensures
218
+ # that only a single source path can map to the corresponding destination path
219
+ bundle_map = BundleMap(
220
+ project_root=project_root, deploy_root=Path(native_app.deploy_root)
221
+ )
222
+ for artifact in native_app.artifacts:
223
+ bundle_map.add(artifact)
224
+
225
+ manifest_path = next(
226
+ (
227
+ src
228
+ for src, dest in bundle_map.all_mappings(
229
+ absolute=True, expand_directories=True
230
+ )
231
+ if dest.name == "manifest.yml"
232
+ ),
233
+ None,
234
+ )
235
+ if not manifest_path:
236
+ # The manifest field is required, so we can't gracefully handle it being missing
237
+ raise ClickException(
238
+ "manifest.yml file not found in any Native App artifact sources, "
239
+ "unable to perform migration"
240
+ )
241
+
242
+ # Use a POSIX path to be consistent with other migrated fields
243
+ # which use POSIX paths as default values
244
+ return manifest_path.relative_to(project_root).as_posix()
245
+
246
+ def _make_template(template: str) -> str:
247
+ return f"{PROJECT_TEMPLATE_VARIABLE_OPENING} {template} {PROJECT_TEMPLATE_VARIABLE_CLOSING}"
248
+
249
+ def _convert_package_script_files(package_scripts: list[str]):
250
+ # PDFv2 doesn't support package scripts, only post-deploy scripts, so we
251
+ # need to convert the Jinja syntax from {{ }} to <% %>
252
+ # Luckily, package scripts only support {{ package_name }}, so let's convert that tag
253
+ # to v2 template syntax by running it though the template process with a fake
254
+ # package name that's actually a valid v2 template, which will be evaluated
255
+ # when the script is used as a post-deploy script
256
+ fake_package_replacement_template = _make_template(
257
+ f"ctx.entities.{package_entity_name}.identifier"
258
+ )
259
+ jinja_context = dict(package_name=fake_package_replacement_template)
260
+ post_deploy_hooks = []
261
+ for script_file in package_scripts:
262
+ new_contents = render_script_template(
263
+ project_root, jinja_context, script_file, get_basic_jinja_env()
264
+ )
265
+ (project_root / script_file).write_text(new_contents)
266
+ post_deploy_hooks.append(SqlScriptHookType(sql_script=script_file))
267
+ return post_deploy_hooks
268
+
269
+ package_entity_name = "pkg"
270
+ if (
271
+ native_app.package
272
+ and native_app.package.name
273
+ and native_app.package.name != PackageV11.model_fields["name"].default
274
+ ):
275
+ package_identifier = native_app.package.name
276
+ else:
277
+ # Backport the PackageV11 default name template, updated for PDFv2
278
+ package_identifier = _make_template(
279
+ f"fn.concat_ids('{native_app.name}', '_pkg_', fn.sanitize_id(fn.get_username('unknown_user')) | lower)"
280
+ )
281
+ package = {
282
+ "type": "application package",
283
+ "identifier": package_identifier,
284
+ "manifest": _find_manifest(),
285
+ "artifacts": native_app.artifacts,
286
+ }
287
+
288
+ if _is_field_defined(template_context, "ctx", "native_app", "bundle_root"):
289
+ package["bundle_root"] = native_app.bundle_root
290
+ if _is_field_defined(template_context, "ctx", "native_app", "generated_root"):
291
+ package["generated_root"] = native_app.generated_root
292
+ if _is_field_defined(template_context, "ctx", "native_app", "deploy_root"):
293
+ package["deploy_root"] = native_app.deploy_root
294
+ if _is_field_defined(template_context, "ctx", "native_app", "source_stage"):
295
+ package["stage"] = native_app.source_stage
296
+ if _is_field_defined(template_context, "ctx", "native_app", "scratch_stage"):
297
+ package["scratch_stage"] = native_app.scratch_stage
298
+
299
+ if native_app.package:
300
+ if _is_field_defined(
301
+ template_context, "ctx", "native_app", "package", "distribution"
302
+ ):
303
+ package["distribution"] = native_app.package.distribution
304
+ package_meta = _make_meta(native_app.package)
305
+ if native_app.package.scripts:
306
+ converted_post_deploy_hooks = _convert_package_script_files(
307
+ native_app.package.scripts
308
+ )
309
+ package_meta["post_deploy"] = (
310
+ package_meta.get("post_deploy", []) + converted_post_deploy_hooks
311
+ )
312
+ if package_meta:
313
+ package["meta"] = package_meta
314
+
315
+ app_entity_name = "app"
316
+ if (
317
+ native_app.application
318
+ and native_app.application.name
319
+ and native_app.application.name != ApplicationV11.model_fields["name"].default
320
+ ):
321
+ app_identifier = native_app.application.name
322
+ else:
323
+ # Backport the ApplicationV11 default name template, updated for PDFv2
324
+ app_identifier = _make_template(
325
+ f"fn.concat_ids('{native_app.name}', '_', fn.sanitize_id(fn.get_username('unknown_user')) | lower)"
326
+ )
327
+ app = {
328
+ "type": "application",
329
+ "identifier": app_identifier,
330
+ "from": {"target": package_entity_name},
331
+ }
332
+ if native_app.application:
333
+ if app_meta := _make_meta(native_app.application):
334
+ app["meta"] = app_meta
335
+ if _is_field_defined(
336
+ template_context, "ctx", "native_app", "application", "debug"
337
+ ):
338
+ app["debug"] = native_app.application.debug
339
+
340
+ return {
341
+ "entities": {
342
+ package_entity_name: package,
343
+ app_entity_name: app,
344
+ }
345
+ }
346
+
347
+
348
+ def convert_envs_to_v2(pd: ProjectDefinition):
349
+ if hasattr(pd, "env") and pd.env:
350
+ data = {k: v for k, v in pd.env.items()}
351
+ return data
352
+ return None
353
+
354
+
355
+ def _check_if_project_definition_meets_requirements(
356
+ pd: ProjectDefinition, accept_templates: bool
357
+ ):
358
+ if pd.meets_version_requirement("2"):
359
+ raise ClickException("Project definition is already at version 2.")
360
+
361
+ if PROJECT_TEMPLATE_VARIABLE_OPENING in str(pd):
362
+ if not accept_templates:
363
+ raise ClickException(
364
+ "Project definition contains templates. They may not be migrated correctly, and require manual migration."
365
+ "You can try again with --accept-templates option, to attempt automatic migration."
366
+ )
367
+ log.warning(
368
+ "Your V1 definition contains templates. We cannot guarantee the correctness of the migration."
369
+ )
370
+
371
+
372
+ def _process_streamlit_files(
373
+ file_name: Optional[str], file_type: Literal["pages", "environment"]
374
+ ):
375
+ default = DEFAULT_PAGES_DIR if file_type == "pages" else DEFAULT_ENV_FILE
376
+
377
+ if file_name and not Path(file_name).exists():
378
+ raise ClickException(f"Provided file {file_name} does not exist")
379
+ elif file_name is None and Path(default).exists():
380
+ file_name = default
381
+ return file_name
382
+
383
+
384
+ def get_list_of_all_entities(
385
+ snowpark_entities: Dict[str, Any],
386
+ streamlit_entities: Dict[str, Any],
387
+ native_app_entities: Dict[str, Any],
388
+ ):
389
+ # Check all combinations of entity types for overlapping names
390
+ # (No need to use itertools here, PDFv1 only supports these three types)
391
+ for types, first, second in [
392
+ ("streamlit and snowpark", streamlit_entities, snowpark_entities),
393
+ ("streamlit and native app", streamlit_entities, native_app_entities),
394
+ ("native app and snowpark", native_app_entities, snowpark_entities),
395
+ ]:
396
+ if first.keys() & second.keys():
397
+ raise ClickException(
398
+ f"In your project, {types} entities share the same name. Please rename them and try again."
399
+ )
400
+ return snowpark_entities | streamlit_entities | native_app_entities
@@ -20,7 +20,10 @@ from pathlib import Path
20
20
  from typing import List, Optional
21
21
 
22
22
  from snowflake.cli.api.project.definition import ProjectProperties, load_project
23
- from snowflake.cli.api.project.schemas.project_definition import ProjectDefinitionV1
23
+ from snowflake.cli.api.project.schemas.project_definition import (
24
+ ProjectDefinition,
25
+ ProjectDefinitionV1,
26
+ )
24
27
  from snowflake.cli.api.utils.types import Context
25
28
 
26
29
 
@@ -38,7 +41,7 @@ class DefinitionManager:
38
41
  USER_DEFINITION_FILENAME = "snowflake.local.yml"
39
42
 
40
43
  project_root: Path
41
- _project_config_paths: List[Path]
44
+ project_config_paths: List[Path]
42
45
 
43
46
  def __init__(
44
47
  self,
@@ -50,12 +53,12 @@ class DefinitionManager:
50
53
  )
51
54
 
52
55
  self.project_root = project_root
53
- self._project_config_paths = self._find_definition_files(self.project_root)
56
+ self.project_config_paths = self._find_definition_files(self.project_root)
54
57
  self._context_overrides = context_overrides
55
58
 
56
59
  @functools.cached_property
57
60
  def has_definition_file(self):
58
- return len(self._project_config_paths) > 0
61
+ return len(self.project_config_paths) > 0
59
62
 
60
63
  @staticmethod
61
64
  def _find_definition_files(project_root: Path) -> List[Path]:
@@ -123,12 +126,20 @@ class DefinitionManager:
123
126
 
124
127
  @functools.cached_property
125
128
  def _project_properties(self) -> ProjectProperties:
126
- return load_project(self._project_config_paths, self._context_overrides)
129
+ return load_project(self.project_config_paths, self._context_overrides)
130
+
131
+ @functools.cached_property
132
+ def _raw_project_data(self) -> ProjectProperties:
133
+ return load_project(self.project_config_paths, {}, False)
127
134
 
128
135
  @functools.cached_property
129
136
  def project_definition(self) -> ProjectDefinitionV1:
130
137
  return self._project_properties.project_definition
131
138
 
139
+ @functools.cached_property
140
+ def unrendered_project_definition(self) -> ProjectDefinition:
141
+ return self._raw_project_data.project_definition
142
+
132
143
  @functools.cached_property
133
144
  def template_context(self) -> Context:
134
145
  return self._project_properties.project_context
@@ -11,13 +11,13 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
-
15
- from snowflake.cli.api.cli_global_context import cli_context
14
+ from snowflake.cli.api.cli_global_context import get_cli_context
16
15
  from snowflake.cli.api.exceptions import NoProjectDefinitionError
17
16
 
18
17
 
19
18
  def assert_project_type(project_type: str):
19
+ cli_context = get_cli_context()
20
20
  if not getattr(cli_context.project_definition, project_type, None):
21
21
  raise NoProjectDefinitionError(
22
- project_type=project_type, project_file=cli_context.project_root
22
+ project_type=project_type, project_root=cli_context.project_root
23
23
  )