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
@@ -15,18 +15,24 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  from abc import ABC
18
- from typing import Generic, List, Optional, TypeVar
18
+ from typing import Dict, Generic, List, Optional, TypeVar, Union
19
19
 
20
- from pydantic import Field
21
- from snowflake.cli.api.project.schemas.native_app.application import (
22
- PostDeployHook,
23
- )
20
+ from pydantic import Field, PrivateAttr, field_validator
21
+ from snowflake.cli.api.identifiers import FQN
24
22
  from snowflake.cli.api.project.schemas.updatable_model import (
25
23
  IdentifierField,
26
24
  UpdatableModel,
27
25
  )
28
26
 
29
27
 
28
+ class SqlScriptHookType(UpdatableModel):
29
+ sql_script: str = Field(title="SQL file path relative to the project root")
30
+
31
+
32
+ # Currently sql_script is the only supported hook type. Change to a Union once other hook types are added
33
+ PostDeployHook = SqlScriptHookType
34
+
35
+
30
36
  class MetaField(UpdatableModel):
31
37
  warehouse: Optional[str] = IdentifierField(
32
38
  title="Warehouse used to run the scripts", default=None
@@ -39,26 +45,59 @@ class MetaField(UpdatableModel):
39
45
  title="Actions that will be executed after the application object is created/upgraded",
40
46
  default=None,
41
47
  )
42
-
43
-
44
- class DefaultsField(UpdatableModel):
45
- schema_: Optional[str] = Field(
46
- title="Schema.",
47
- alias="schema",
48
- default=None,
49
- )
50
- stage: Optional[str] = Field(
51
- title="Stage.",
48
+ use_mixins: Optional[List[str]] = Field(
49
+ title="Name of the mixin used to fill the entity fields",
52
50
  default=None,
53
51
  )
54
52
 
53
+ @field_validator("use_mixins", mode="before")
54
+ @classmethod
55
+ def ensure_use_mixins_is_a_list(
56
+ cls, mixins: Optional[str | List[str]]
57
+ ) -> Optional[List[str]]:
58
+ if isinstance(mixins, str):
59
+ return [mixins]
60
+ return mixins
61
+
55
62
 
56
- class EntityBase(ABC, UpdatableModel):
63
+ class Identifier(UpdatableModel):
64
+ name: str = Field(title="Entity name")
65
+ schema_: Optional[str] = Field(title="Entity schema", alias="schema", default=None)
66
+ database: Optional[str] = Field(title="Entity database", default=None)
67
+
68
+
69
+ class EntityModelBase(ABC, UpdatableModel):
57
70
  @classmethod
58
71
  def get_type(cls) -> str:
59
72
  return cls.model_fields["type"].annotation.__args__[0]
60
73
 
61
74
  meta: Optional[MetaField] = Field(title="Meta fields", default=None)
75
+ identifier: Optional[Union[Identifier | str]] = Field(
76
+ title="Entity identifier", default=None
77
+ )
78
+ # Set by parent model in post validation. To reference it use `entity_id`.
79
+ _entity_id: str = PrivateAttr(default=None)
80
+
81
+ @property
82
+ def entity_id(self):
83
+ return self._entity_id
84
+
85
+ def set_entity_id(self, value: str):
86
+ self._entity_id = value
87
+
88
+ def validate_identifier(self):
89
+ """Helper that's used by ProjectDefinition validator."""
90
+ if not self._entity_id and not self.identifier:
91
+ raise ValueError("Missing entity identifier")
92
+
93
+ @property
94
+ def fqn(self) -> FQN:
95
+ if isinstance(self.identifier, str):
96
+ return FQN.from_string(self.identifier)
97
+ if isinstance(self.identifier, Identifier):
98
+ return FQN.from_identifier_model_v2(self.identifier)
99
+ if self.entity_id:
100
+ return FQN.from_string(self.entity_id)
62
101
 
63
102
 
64
103
  TargetType = TypeVar("TargetType")
@@ -76,3 +115,39 @@ class TargetField(UpdatableModel, Generic[TargetType]):
76
115
  them in __pydantic_generic_metadata__
77
116
  """
78
117
  return self.__pydantic_generic_metadata__["args"][0]
118
+
119
+
120
+ class ImportsBaseModel:
121
+ imports: Optional[List[str]] = Field(
122
+ title="Stage and path to previously uploaded files you want to import",
123
+ default=[],
124
+ )
125
+
126
+ def get_imports_sql(self) -> str | None:
127
+ if not self.imports:
128
+ return None
129
+ imports = ", ".join(f"'{i}'" for i in self.imports)
130
+ return f"IMPORTS = ({imports})"
131
+
132
+
133
+ class ExternalAccessBaseModel:
134
+ external_access_integrations: Optional[List[str]] = Field(
135
+ title="Names of external access integrations needed for this entity to access external networks",
136
+ default=[],
137
+ )
138
+ secrets: Optional[Dict[str, str]] = Field(
139
+ title="Assigns the names of secrets to variables so that you can use the variables to reference the secrets",
140
+ default={},
141
+ )
142
+
143
+ def get_external_access_integrations_sql(self) -> str | None:
144
+ if not self.external_access_integrations:
145
+ return None
146
+ external_access_integration_name = ", ".join(self.external_access_integrations)
147
+ return f"external_access_integrations=({external_access_integration_name})"
148
+
149
+ def get_secrets_sql(self) -> str | None:
150
+ if not self.secrets:
151
+ return None
152
+ secrets = ", ".join(f"'{key}'={value}" for key, value in self.secrets.items())
153
+ return f"secrets=({secrets})"
@@ -14,17 +14,48 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- from typing import Union, get_args
17
+ from typing import Dict, List, Union, get_args
18
18
 
19
- from snowflake.cli.api.project.schemas.entities.application_entity import (
19
+ from snowflake.cli._plugins.nativeapp.entities.application import (
20
20
  ApplicationEntity,
21
+ ApplicationEntityModel,
21
22
  )
22
- from snowflake.cli.api.project.schemas.entities.application_package_entity import (
23
+ from snowflake.cli._plugins.nativeapp.entities.application_package import (
23
24
  ApplicationPackageEntity,
25
+ ApplicationPackageEntityModel,
26
+ )
27
+ from snowflake.cli._plugins.snowpark.snowpark_entity import (
28
+ FunctionEntity,
29
+ ProcedureEntity,
30
+ )
31
+ from snowflake.cli._plugins.snowpark.snowpark_entity_model import (
32
+ FunctionEntityModel,
33
+ ProcedureEntityModel,
34
+ )
35
+ from snowflake.cli._plugins.streamlit.streamlit_entity import StreamlitEntity
36
+ from snowflake.cli._plugins.streamlit.streamlit_entity_model import (
37
+ StreamlitEntityModel,
24
38
  )
25
39
 
26
- Entity = Union[ApplicationEntity, ApplicationPackageEntity]
40
+ Entity = Union[
41
+ ApplicationEntity,
42
+ ApplicationPackageEntity,
43
+ StreamlitEntity,
44
+ ProcedureEntity,
45
+ FunctionEntity,
46
+ ]
47
+ EntityModel = Union[
48
+ ApplicationEntityModel,
49
+ ApplicationPackageEntityModel,
50
+ StreamlitEntityModel,
51
+ FunctionEntityModel,
52
+ ProcedureEntityModel,
53
+ ]
27
54
 
28
- ALL_ENTITIES = [*get_args(Entity)]
55
+ ALL_ENTITIES: List[Entity] = [*get_args(Entity)]
56
+ ALL_ENTITY_MODELS: List[EntityModel] = [*get_args(EntityModel)]
29
57
 
30
- v2_entity_types_map = {e.get_type(): e for e in ALL_ENTITIES}
58
+ v2_entity_model_types_map = {e.get_type(): e for e in ALL_ENTITY_MODELS}
59
+ v2_entity_model_to_entity_map: Dict[EntityModel, Entity] = {
60
+ e.get_entity_model_type(): e for e in ALL_ENTITIES
61
+ }
@@ -15,33 +15,32 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  from dataclasses import dataclass
18
- from typing import Dict, Optional, Union
18
+ from typing import Any, Dict, List, Optional, Union
19
19
 
20
20
  from packaging.version import Version
21
21
  from pydantic import Field, ValidationError, field_validator, model_validator
22
- from snowflake.cli.api.feature_flags import FeatureFlag
22
+ from snowflake.cli._plugins.nativeapp.entities.application import ApplicationEntityModel
23
23
  from snowflake.cli.api.project.errors import SchemaValidationError
24
- from snowflake.cli.api.project.schemas.entities.application_entity import (
25
- ApplicationEntity,
26
- )
27
24
  from snowflake.cli.api.project.schemas.entities.common import (
28
- DefaultsField,
29
25
  TargetField,
30
26
  )
31
27
  from snowflake.cli.api.project.schemas.entities.entities import (
32
- Entity,
33
- v2_entity_types_map,
28
+ EntityModel,
29
+ v2_entity_model_types_map,
34
30
  )
35
- from snowflake.cli.api.project.schemas.native_app.native_app import (
31
+ from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
32
+ from snowflake.cli.api.project.schemas.v1.native_app.native_app import (
36
33
  NativeApp,
37
34
  NativeAppV11,
38
35
  )
39
- from snowflake.cli.api.project.schemas.snowpark.snowpark import Snowpark
40
- from snowflake.cli.api.project.schemas.streamlit.streamlit import Streamlit
41
- from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
36
+ from snowflake.cli.api.project.schemas.v1.snowpark.snowpark import Snowpark
37
+ from snowflake.cli.api.project.schemas.v1.streamlit.streamlit import Streamlit
42
38
  from snowflake.cli.api.utils.types import Context
43
39
  from typing_extensions import Annotated
44
40
 
41
+ AnnotatedEntity = Annotated[EntityModel, Field(discriminator="type")]
42
+ scalar = str | int | float | bool
43
+
45
44
 
46
45
  @dataclass
47
46
  class ProjectProperties:
@@ -61,6 +60,11 @@ class ProjectProperties:
61
60
  project_context: Context
62
61
 
63
62
 
63
+ @dataclass
64
+ class YamlOverride:
65
+ data: dict | list
66
+
67
+
64
68
  class _ProjectDefinitionBase(UpdatableModel):
65
69
  def __init__(self, *args, **kwargs):
66
70
  try:
@@ -111,46 +115,43 @@ class DefinitionV11(DefinitionV10):
111
115
 
112
116
 
113
117
  class DefinitionV20(_ProjectDefinitionBase):
114
- entities: Dict[str, Annotated[Entity, Field(discriminator="type")]] = Field(
115
- title="Entity definitions."
116
- )
118
+ entities: Dict[str, AnnotatedEntity] = Field(title="Entity definitions.")
117
119
 
118
- @model_validator(mode="before")
119
- @classmethod
120
- def apply_defaults(cls, data: Dict) -> Dict:
121
- """
122
- Applies default values that exist on the model but not specified in yml
123
- """
124
- if "defaults" in data and "entities" in data:
125
- for key, entity in data["entities"].items():
126
- entity_type = entity["type"]
127
- if entity_type not in v2_entity_types_map:
128
- continue
129
- entity_model = v2_entity_types_map[entity_type]
130
- for default_key, default_value in data["defaults"].items():
131
- if (
132
- default_key in entity_model.model_fields
133
- and default_key not in entity
134
- ):
135
- entity[default_key] = default_value
136
- return data
120
+ @model_validator(mode="after")
121
+ def validate_entities_identifiers(self):
122
+ for key, entity in self.entities.items():
123
+ entity.set_entity_id(key)
124
+ entity.validate_identifier()
125
+ return self
137
126
 
138
127
  @field_validator("entities", mode="after")
139
128
  @classmethod
140
- def validate_entities(cls, entities: Dict[str, Entity]) -> Dict[str, Entity]:
129
+ def validate_entities(
130
+ cls, entities: Dict[str, AnnotatedEntity]
131
+ ) -> Dict[str, AnnotatedEntity]:
141
132
  for key, entity in entities.items():
142
133
  # TODO Automatically detect TargetFields to validate
143
- if entity.type == ApplicationEntity.get_type():
144
- if isinstance(entity.from_, TargetField):
145
- target_key = entity.from_.target
146
- target_object = entity.from_
147
- target_type = target_object.get_type()
148
- cls._validate_target_field(target_key, target_type, entities)
134
+ if isinstance(entity, list):
135
+ for e in entity:
136
+ cls._validate_single_entity(e, entities)
137
+ else:
138
+ cls._validate_single_entity(entity, entities)
149
139
  return entities
150
140
 
141
+ @classmethod
142
+ def _validate_single_entity(
143
+ cls, entity: EntityModel, entities: Dict[str, AnnotatedEntity]
144
+ ):
145
+ if entity.type == ApplicationEntityModel.get_type():
146
+ if isinstance(entity.from_, TargetField):
147
+ target_key = entity.from_.target
148
+ target_object = entity.from_
149
+ target_type = target_object.get_type()
150
+ cls._validate_target_field(target_key, target_type, entities)
151
+
151
152
  @classmethod
152
153
  def _validate_target_field(
153
- cls, target_key: str, target_type: Entity, entities: Dict[str, Entity]
154
+ cls, target_key: str, target_type: EntityModel, entities: Dict[str, EntityModel]
154
155
  ):
155
156
  if target_key not in entities:
156
157
  raise ValueError(f"No such target: {target_key}")
@@ -162,16 +163,114 @@ class DefinitionV20(_ProjectDefinitionBase):
162
163
  f"Target type mismatch. Expected {target_type.__name__}, got {actual_target_type.__name__}"
163
164
  )
164
165
 
165
- defaults: Optional[DefaultsField] = Field(
166
- title="Default key/value entity values that are merged recursively for each entity.",
166
+ env: Optional[Dict[str, Union[str, int, bool]]] = Field(
167
+ title="Default environment specification for this project.",
167
168
  default=None,
168
169
  )
169
170
 
170
- env: Optional[Dict[str, Union[str, int, bool]]] = Field(
171
- title="Default environment specification for this project.",
171
+ mixins: Optional[Dict[str, Dict]] = Field(
172
+ title="Mixins to apply to entities",
172
173
  default=None,
173
174
  )
174
175
 
176
+ @model_validator(mode="before")
177
+ @classmethod
178
+ def apply_mixins(cls, data: Dict) -> Dict:
179
+ """
180
+ Applies mixins to those entities, whose meta field contains the mixin name.
181
+ """
182
+ if "mixins" not in data or "entities" not in data:
183
+ return data
184
+
185
+ entities = data["entities"]
186
+ for entity_name, entity in entities.items():
187
+ entity_mixins = entity_mixins_to_list(
188
+ entity.get("meta", {}).get("use_mixins")
189
+ )
190
+
191
+ merged_values = cls._merge_mixins_with_entity(
192
+ entity_id=entity_name,
193
+ entity=entity,
194
+ entity_mixins_names=entity_mixins,
195
+ mixin_defs=data["mixins"],
196
+ )
197
+ entities[entity_name] = merged_values
198
+ return data
199
+
200
+ @classmethod
201
+ def _merge_mixins_with_entity(
202
+ cls,
203
+ entity_id: str,
204
+ entity: dict,
205
+ entity_mixins_names: list,
206
+ mixin_defs: dict,
207
+ ) -> dict:
208
+ # Validate mixins
209
+ for mixin_name in entity_mixins_names:
210
+ if mixin_name not in mixin_defs:
211
+ raise ValueError(f"Mixin {mixin_name} not defined")
212
+
213
+ # Build object override data from mixins
214
+ data: dict = {}
215
+ for mx_name in entity_mixins_names:
216
+ data = cls._merge_data(data, mixin_defs[mx_name])
217
+
218
+ for key, override_value in data.items():
219
+ if key not in get_allowed_fields_for_entity(entity):
220
+ raise ValueError(
221
+ f"Unsupported key '{key}' for entity {entity_id} of type {entity['type']} "
222
+ )
223
+
224
+ entity_value = entity.get(key)
225
+ if (
226
+ entity_value is not None
227
+ and not isinstance(entity_value, YamlOverride)
228
+ and not isinstance(entity_value, type(override_value))
229
+ ):
230
+ raise ValueError(
231
+ f"Value from mixins for property {key} is of type '{type(override_value).__name__}' "
232
+ f"while entity {entity_id} expects value of type '{type(entity_value).__name__}'"
233
+ )
234
+
235
+ # Apply entity data on top of mixins
236
+ data = cls._merge_data(data, entity)
237
+ return data
238
+
239
+ @classmethod
240
+ def _merge_data(
241
+ cls,
242
+ left: dict | list | scalar | None,
243
+ right: dict | list | scalar | None | YamlOverride,
244
+ ):
245
+ """
246
+ Merges right data into left. Right and left is expected to be of the same type, if not right is returned.
247
+ If left is sequence then missing elements from right are appended.
248
+ If left is dictionary then we update it with data from right. The update is done recursively key by key.
249
+ """
250
+ if isinstance(right, YamlOverride):
251
+ return right.data
252
+
253
+ if left is None:
254
+ return right
255
+
256
+ # At that point left and right are of the same type
257
+ if isinstance(left, dict) and isinstance(right, dict):
258
+ data = dict(left)
259
+ for key in right:
260
+ data[key] = cls._merge_data(left=data.get(key), right=right[key])
261
+ return data
262
+
263
+ if isinstance(left, list) and isinstance(right, list):
264
+ return _unique_extend(left, right)
265
+
266
+ if not isinstance(right, type(left)):
267
+ raise ValueError(f"Could not merge {type(right)} and {type(left)}.")
268
+
269
+ return right
270
+
271
+ def get_entities_by_type(self, entity_type: str):
272
+ return {i: e for i, e in self.entities.items() if e.get_type() == entity_type}
273
+
175
274
 
176
275
  def build_project_definition(**data) -> ProjectDefinition:
177
276
  """
@@ -193,7 +292,39 @@ ProjectDefinition = Union[ProjectDefinitionV1, ProjectDefinitionV2]
193
292
 
194
293
 
195
294
  def get_version_map():
196
- version_map = {"1": DefinitionV10, "1.1": DefinitionV11}
197
- if FeatureFlag.ENABLE_PROJECT_DEFINITION_V2.is_enabled():
198
- version_map["2"] = DefinitionV20
295
+ version_map = {"1": DefinitionV10, "1.1": DefinitionV11, "2": DefinitionV20}
199
296
  return version_map
297
+
298
+
299
+ def entity_mixins_to_list(entity_mixins: Optional[str | List[str]]) -> List[str]:
300
+ """
301
+ Convert an optional string or a list of strings to a list of strings.
302
+ """
303
+ if entity_mixins is None:
304
+ return []
305
+ if isinstance(entity_mixins, str):
306
+ return [entity_mixins]
307
+ return entity_mixins
308
+
309
+
310
+ def get_allowed_fields_for_entity(entity: Dict[str, Any]) -> List[str]:
311
+ """
312
+ Get the allowed fields for the given entity.
313
+ """
314
+ entity_type = entity.get("type")
315
+ if entity_type is None:
316
+ raise ValueError("Entity is missing type declaration.")
317
+
318
+ if entity_type not in v2_entity_model_types_map:
319
+ return []
320
+
321
+ entity_model = v2_entity_model_types_map[entity_type]
322
+ return entity_model.model_fields
323
+
324
+
325
+ def _unique_extend(list_a: List, list_b: List) -> List:
326
+ new_list = list(list_a)
327
+ for item in list_b:
328
+ if item not in list_a:
329
+ new_list.append(item)
330
+ return new_list
@@ -117,6 +117,7 @@ class UpdatableModel(BaseModel):
117
117
  # all the values of the class attributes. We go in reverse order so that
118
118
  # values in subclasses overrides values from parent classes in case of field overrides.
119
119
 
120
+ private_attrs = set()
120
121
  for class_ in reversed(cls.__mro__):
121
122
  class_dict = class_.__dict__
122
123
  field_annotations.update(class_dict.get("__annotations__", {}))
@@ -128,10 +129,15 @@ class UpdatableModel(BaseModel):
128
129
  else:
129
130
  # If Pydantic did not process this class yet, get the values from class_dict directly
130
131
  field_values.update(class_dict)
132
+ for pa in class_dict.get("__private_attributes__", []):
133
+ private_attrs.add(pa)
131
134
 
132
135
  # Add Pydantic validation wrapper around all fields except `DiscriminatorField`s
133
136
  for field_name in field_annotations:
134
- if not cls._is_entity_type_field(field_values.get(field_name)):
137
+ if field_name in private_attrs:
138
+ continue
139
+ field = field_values.get(field_name)
140
+ if not cls._is_entity_type_field(field):
135
141
  cls._add_validator(field_name)
136
142
 
137
143
  @classmethod
@@ -154,7 +160,8 @@ class UpdatableModel(BaseModel):
154
160
 
155
161
  setattr(
156
162
  cls,
157
- f"_field_validator_with_verbose_name_to_avoid_name_conflict_{field_name}",
163
+ # Unique name so that subclasses get a unique instance of this validator
164
+ f"_{cls.__module__}.{cls.__name__}_validate_{field_name}",
158
165
  field_validator(field_name, mode="wrap")(validator_skipping_templated_str),
159
166
  )
160
167
 
@@ -187,7 +194,8 @@ def DiscriminatorField(*args, **kwargs): # noqa N802
187
194
  When this `DiscriminatorField` is used on a pydantic attribute,
188
195
  we will not allow templating on it.
189
196
  """
190
- return Field(is_discriminator_field=True, *args, **kwargs)
197
+ extra = dict(is_discriminator_field=True)
198
+ return Field(json_schema_extra=extra, *args, **kwargs)
191
199
 
192
200
 
193
201
  def IdentifierField(*args, **kwargs): # noqa N802
File without changes
@@ -17,7 +17,9 @@ from __future__ import annotations
17
17
  from typing import Optional, cast
18
18
 
19
19
  from pydantic import Field
20
- from snowflake.cli.api.project.schemas.updatable_model import IdentifierField
20
+ from snowflake.cli.api.project.schemas.updatable_model import (
21
+ IdentifierField,
22
+ )
21
23
 
22
24
 
23
25
  class ObjectIdentifierBaseModel:
@@ -16,19 +16,13 @@ from __future__ import annotations
16
16
 
17
17
  from typing import List, Optional
18
18
 
19
- from pydantic import Field
19
+ from pydantic import Field, field_validator
20
+ from snowflake.cli.api.project.schemas.entities.common import PostDeployHook
20
21
  from snowflake.cli.api.project.schemas.updatable_model import (
21
22
  IdentifierField,
22
23
  UpdatableModel,
23
24
  )
24
-
25
-
26
- class SqlScriptHookType(UpdatableModel):
27
- sql_script: str = Field(title="SQL file path relative to the project root")
28
-
29
-
30
- # Currently sql_script is the only supported hook type. Change to a Union once other hook types are added
31
- PostDeployHook = SqlScriptHookType
25
+ from snowflake.cli.api.project.util import append_test_resource_suffix
32
26
 
33
27
 
34
28
  class Application(UpdatableModel):
@@ -53,6 +47,11 @@ class Application(UpdatableModel):
53
47
  default=None,
54
48
  )
55
49
 
50
+ @field_validator("name")
51
+ @classmethod
52
+ def append_test_resource_suffix_to_name(cls, input_value: str) -> str:
53
+ return append_test_resource_suffix(input_value)
54
+
56
55
 
57
56
  class ApplicationV11(Application):
58
57
  # Templated defaults only supported in v1.1+
@@ -18,13 +18,13 @@ import re
18
18
  from typing import List, Optional, Union
19
19
 
20
20
  from pydantic import Field, field_validator
21
- from snowflake.cli.api.project.schemas.native_app.application import (
21
+ from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
22
+ from snowflake.cli.api.project.schemas.v1.native_app.application import (
22
23
  Application,
23
24
  ApplicationV11,
24
25
  )
25
- from snowflake.cli.api.project.schemas.native_app.package import Package, PackageV11
26
- from snowflake.cli.api.project.schemas.native_app.path_mapping import PathMapping
27
- from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
26
+ from snowflake.cli.api.project.schemas.v1.native_app.package import Package, PackageV11
27
+ from snowflake.cli.api.project.schemas.v1.native_app.path_mapping import PathMapping
28
28
  from snowflake.cli.api.project.util import (
29
29
  SCHEMA_AND_NAME,
30
30
  )
@@ -17,11 +17,12 @@ from __future__ import annotations
17
17
  from typing import List, Literal, Optional
18
18
 
19
19
  from pydantic import Field, field_validator, model_validator
20
- from snowflake.cli.api.project.schemas.native_app.application import PostDeployHook
20
+ from snowflake.cli.api.project.schemas.entities.common import PostDeployHook
21
21
  from snowflake.cli.api.project.schemas.updatable_model import (
22
22
  IdentifierField,
23
23
  UpdatableModel,
24
24
  )
25
+ from snowflake.cli.api.project.util import append_test_resource_suffix
25
26
 
26
27
  DistributionOptions = Literal["internal", "external", "INTERNAL", "EXTERNAL"]
27
28
 
@@ -50,6 +51,11 @@ class Package(UpdatableModel):
50
51
  default=None,
51
52
  )
52
53
 
54
+ @field_validator("name")
55
+ @classmethod
56
+ def append_test_resource_suffix_to_name(cls, input_value: str) -> str:
57
+ return append_test_resource_suffix(input_value)
58
+
53
59
  @field_validator("scripts")
54
60
  @classmethod
55
61
  def validate_scripts(cls, input_list):
@@ -17,9 +17,9 @@ from __future__ import annotations
17
17
  from typing import Dict, List, Optional, Union
18
18
 
19
19
  from pydantic import Field, field_validator
20
- from snowflake.cli.api.project.schemas.identifier_model import ObjectIdentifierModel
21
- from snowflake.cli.api.project.schemas.snowpark.argument import Argument
22
20
  from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
21
+ from snowflake.cli.api.project.schemas.v1.identifier_model import ObjectIdentifierModel
22
+ from snowflake.cli.api.project.schemas.v1.snowpark.argument import Argument
23
23
 
24
24
 
25
25
  class _CallableBase(UpdatableModel):
@@ -17,11 +17,11 @@ from __future__ import annotations
17
17
  from typing import List, Optional
18
18
 
19
19
  from pydantic import Field
20
- from snowflake.cli.api.project.schemas.snowpark.callable import (
20
+ from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
21
+ from snowflake.cli.api.project.schemas.v1.snowpark.callable import (
21
22
  FunctionSchema,
22
23
  ProcedureSchema,
23
24
  )
24
- from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
25
25
 
26
26
 
27
27
  class Snowpark(UpdatableModel):
@@ -18,8 +18,8 @@ from pathlib import Path
18
18
  from typing import List, Optional
19
19
 
20
20
  from pydantic import Field
21
- from snowflake.cli.api.project.schemas.identifier_model import ObjectIdentifierModel
22
21
  from snowflake.cli.api.project.schemas.updatable_model import UpdatableModel
22
+ from snowflake.cli.api.project.schemas.v1.identifier_model import ObjectIdentifierModel
23
23
 
24
24
 
25
25
  class Streamlit(UpdatableModel, ObjectIdentifierModel(object_name="Streamlit")): # type: ignore
@@ -44,3 +44,4 @@ class Streamlit(UpdatableModel, ObjectIdentifierModel(object_name="Streamlit")):
44
44
  title: Optional[str] = Field(
45
45
  title="Human-readable title for the Streamlit dashboard", default=None
46
46
  )
47
+ comment: Optional[str] = Field(title="Comment for the Streamlit app", default=None)