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,74 @@
1
+ from pathlib import Path
2
+ from typing import Dict
3
+
4
+ from snowflake.cli._plugins.workspace.action_context import ActionContext
5
+ from snowflake.cli.api.cli_global_context import get_cli_context
6
+ from snowflake.cli.api.console import cli_console as cc
7
+ from snowflake.cli.api.entities.common import EntityActions, get_sql_executor
8
+ from snowflake.cli.api.exceptions import InvalidProjectDefinitionVersionError
9
+ from snowflake.cli.api.project.definition import default_role
10
+ from snowflake.cli.api.project.schemas.entities.entities import (
11
+ Entity,
12
+ v2_entity_model_to_entity_map,
13
+ )
14
+ from snowflake.cli.api.project.schemas.project_definition import (
15
+ DefinitionV20,
16
+ ProjectDefinition,
17
+ )
18
+ from snowflake.cli.api.project.util import to_identifier
19
+
20
+
21
+ class WorkspaceManager:
22
+ """
23
+ Instantiates entity instances from entity models, providing higher-order functionality on entity compositions.
24
+ """
25
+
26
+ def __init__(self, project_definition: ProjectDefinition, project_root: Path):
27
+ if not project_definition.meets_version_requirement("2"):
28
+ raise InvalidProjectDefinitionVersionError(
29
+ "2.x", project_definition.definition_version
30
+ )
31
+ self._entities_cache: Dict[str, Entity] = {}
32
+ self._project_definition: DefinitionV20 = project_definition
33
+ self._project_root = project_root
34
+ self._default_role = default_role()
35
+ if self._default_role is None:
36
+ self._default_role = get_sql_executor().current_role()
37
+ self.default_warehouse = None
38
+ cli_context = get_cli_context()
39
+ if cli_context.connection.warehouse:
40
+ self.default_warehouse = to_identifier(cli_context.connection.warehouse)
41
+
42
+ def get_entity(self, entity_id: str):
43
+ """
44
+ Returns an entity instance with the given ID. If exists, reuses the previously returned instance, or instantiates a new one otherwise.
45
+ """
46
+ if entity_id in self._entities_cache:
47
+ return self._entities_cache[entity_id]
48
+ entity_model = self._project_definition.entities.get(entity_id, None)
49
+ if entity_model is None:
50
+ raise ValueError(f"No such entity ID: {entity_id}")
51
+ entity_model_cls = entity_model.__class__
52
+ entity_cls = v2_entity_model_to_entity_map[entity_model_cls]
53
+ self._entities_cache[entity_id] = entity_cls(entity_model)
54
+ return self._entities_cache[entity_id]
55
+
56
+ def perform_action(self, entity_id: str, action: EntityActions, *args, **kwargs):
57
+ """
58
+ Instantiates an entity of the given ID and calls the given action on it.
59
+ """
60
+ entity = self.get_entity(entity_id)
61
+ if entity.supports(action):
62
+ action_ctx = ActionContext(
63
+ console=cc,
64
+ project_root=self.project_root(),
65
+ default_role=self._default_role,
66
+ default_warehouse=self.default_warehouse,
67
+ get_entity=self.get_entity,
68
+ )
69
+ return entity.perform(action, action_ctx, *args, **kwargs)
70
+ else:
71
+ raise ValueError(f'This entity type does not support "{action.value}"')
72
+
73
+ def project_root(self) -> Path:
74
+ return self._project_root
@@ -0,0 +1,30 @@
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 snowflake.cli._plugins.workspace import commands
16
+ from snowflake.cli.api.plugins.command import (
17
+ SNOWCLI_ROOT_COMMAND_PATH,
18
+ CommandSpec,
19
+ CommandType,
20
+ plugin_hook_impl,
21
+ )
22
+
23
+
24
+ @plugin_hook_impl
25
+ def command_spec():
26
+ return CommandSpec(
27
+ parent_command_path=SNOWCLI_ROOT_COMMAND_PATH,
28
+ command_type=CommandType.COMMAND_GROUP,
29
+ typer_instance=commands.ws.create_instance(),
30
+ )
@@ -14,324 +14,129 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- import re
17
+ from contextlib import contextmanager
18
+ from contextvars import ContextVar
19
+ from dataclasses import dataclass, field, replace
18
20
  from pathlib import Path
19
- from typing import Callable, Optional
21
+ from typing import TYPE_CHECKING, Iterator
20
22
 
21
- from snowflake.cli.api.exceptions import InvalidSchemaError
23
+ from snowflake.cli.api.connections import ConnectionContext, OpenConnectionCache
24
+ from snowflake.cli.api.exceptions import MissingConfiguration
25
+ from snowflake.cli.api.metrics import CLIMetrics
22
26
  from snowflake.cli.api.output.formats import OutputFormat
23
- from snowflake.cli.api.project.schemas.project_definition import ProjectDefinition
27
+ from snowflake.cli.api.rendering.jinja import CONTEXT_KEY
24
28
  from snowflake.connector import SnowflakeConnection
25
29
 
26
- schema_pattern = re.compile(r".+\..+")
27
-
28
-
29
- class _ConnectionContext:
30
- def __init__(self):
31
- self._cached_connection: Optional[SnowflakeConnection] = None
32
-
33
- self._connection_name: Optional[str] = None
34
- self._account: Optional[str] = None
35
- self._database: Optional[str] = None
36
- self._role: Optional[str] = None
37
- self._schema: Optional[str] = None
38
- self._user: Optional[str] = None
39
- self._password: Optional[str] = None
40
- self._authenticator: Optional[str] = None
41
- self._private_key_path: Optional[str] = None
42
- self._warehouse: Optional[str] = None
43
- self._mfa_passcode: Optional[str] = None
44
- self._enable_diag: Optional[bool] = False
45
- self._diag_log_path: Optional[Path] = None
46
- self._diag_allowlist_path: Optional[Path] = None
47
- self._temporary_connection: bool = False
48
- self._session_token: Optional[str] = None
49
- self._master_token: Optional[str] = None
50
- self._token_file_path: Optional[Path] = None
51
-
52
- def __setattr__(self, key, value):
53
- """
54
- We invalidate connection cache every time connection attributes change.
55
- """
56
- super().__setattr__(key, value)
57
- if key != "_cached_connection":
58
- self._cached_connection = None
59
-
60
- @property
61
- def connection_name(self) -> Optional[str]:
62
- return self._connection_name
63
-
64
- def set_connection_name(self, value: Optional[str]):
65
- self._connection_name = value
66
-
67
- @property
68
- def account(self) -> Optional[str]:
69
- return self._account
70
-
71
- def set_account(self, value: Optional[str]):
72
- self._account = value
73
-
74
- @property
75
- def database(self) -> Optional[str]:
76
- return self._database
77
-
78
- def set_database(self, value: Optional[str]):
79
- self._database = value
80
-
81
- @property
82
- def role(self) -> Optional[str]:
83
- return self._role
84
-
85
- def set_role(self, value: Optional[str]):
86
- self._role = value
30
+ if TYPE_CHECKING:
31
+ from snowflake.cli.api.project.definition_manager import DefinitionManager
32
+ from snowflake.cli.api.project.schemas.project_definition import ProjectDefinition
87
33
 
88
- @property
89
- def schema(self) -> Optional[str]:
90
- return self._schema
91
-
92
- def set_schema(self, value: Optional[str]):
93
- if (
94
- value
95
- and not (value.startswith('"') and value.endswith('"'))
96
- # if schema is fully qualified name (db.schema)
97
- and schema_pattern.match(value)
98
- ):
99
- raise InvalidSchemaError(value)
100
- self._schema = value
101
-
102
- @property
103
- def user(self) -> Optional[str]:
104
- return self._user
105
-
106
- def set_user(self, value: Optional[str]):
107
- self._user = value
108
-
109
- @property
110
- def password(self) -> Optional[str]:
111
- return self._password
112
-
113
- def set_password(self, value: Optional[str]):
114
- self._password = value
115
-
116
- @property
117
- def authenticator(self) -> Optional[str]:
118
- return self._authenticator
119
-
120
- def set_authenticator(self, value: Optional[str]):
121
- self._authenticator = value
122
-
123
- @property
124
- def private_key_path(self) -> Optional[str]:
125
- return self._private_key_path
126
-
127
- def set_private_key_path(self, value: Optional[str]):
128
- self._private_key_path = value
129
-
130
- @property
131
- def warehouse(self) -> Optional[str]:
132
- return self._warehouse
133
-
134
- def set_warehouse(self, value: Optional[str]):
135
- self._warehouse = value
136
-
137
- @property
138
- def mfa_passcode(self) -> Optional[str]:
139
- return self._mfa_passcode
140
-
141
- def set_mfa_passcode(self, value: Optional[str]):
142
- self._mfa_passcode = value
143
-
144
- @property
145
- def enable_diag(self) -> Optional[bool]:
146
- return self._enable_diag
147
-
148
- def set_enable_diag(self, value: Optional[bool]):
149
- self._enable_diag = value
150
-
151
- @property
152
- def diag_log_path(self) -> Optional[Path]:
153
- return self._diag_log_path
154
-
155
- def set_diag_log_path(self, value: Optional[Path]):
156
- self._diag_log_path = value
157
-
158
- @property
159
- def diag_allowlist_path(self) -> Optional[Path]:
160
- return self._diag_allowlist_path
161
-
162
- def set_diag_allowlist_path(self, value: Optional[Path]):
163
- self._diag_allowlist_path = value
164
-
165
- @property
166
- def temporary_connection(self) -> bool:
167
- return self._temporary_connection
168
-
169
- def set_temporary_connection(self, value: bool):
170
- self._temporary_connection = value
171
-
172
- @property
173
- def session_token(self) -> Optional[str]:
174
- return self._session_token
175
-
176
- def set_session_token(self, value: Optional[str]):
177
- self._session_token = value
178
-
179
- @property
180
- def master_token(self) -> Optional[str]:
181
- return self._master_token
182
-
183
- def set_master_token(self, value: Optional[str]):
184
- self._master_token = value
185
-
186
- @property
187
- def token_file_path(self) -> Optional[Path]:
188
- return self._token_file_path
189
-
190
- def set_token_file_path(self, value: Optional[Path]):
191
- self._token_file_path = value
192
-
193
- @property
194
- def connection(self) -> SnowflakeConnection:
195
- if not self._cached_connection:
196
- self._cached_connection = self._build_connection()
197
- return self._cached_connection
198
-
199
- def _collect_not_empty_connection_attributes(self):
200
- return {
201
- "account": self.account,
202
- "user": self.user,
203
- "password": self.password,
204
- "authenticator": self.authenticator,
205
- "private_key_path": self.private_key_path,
206
- "database": self.database,
207
- "schema": self.schema,
208
- "role": self.role,
209
- "warehouse": self.warehouse,
210
- "session_token": self.session_token,
211
- "master_token": self.master_token,
212
- "token_file_path": self.token_file_path,
213
- }
214
-
215
- def _build_connection(self):
216
- from snowflake.cli.app.snow_connector import connect_to_snowflake
217
-
218
- return connect_to_snowflake(
219
- temporary_connection=self.temporary_connection,
220
- mfa_passcode=self._mfa_passcode,
221
- enable_diag=self._enable_diag,
222
- diag_log_path=self._diag_log_path,
223
- diag_allowlist_path=self._diag_allowlist_path,
224
- connection_name=self.connection_name,
225
- **self._collect_not_empty_connection_attributes(),
226
- )
34
+ _CONNECTION_CACHE = OpenConnectionCache()
227
35
 
228
36
 
37
+ @dataclass
229
38
  class _CliGlobalContextManager:
230
- def __init__(self):
231
- self._connection_context = _ConnectionContext()
232
- self._enable_tracebacks = True
233
- self._output_format = OutputFormat.TABLE
234
- self._verbose = False
235
- self._experimental = False
236
- self._project_definition = None
237
- self._project_root = None
238
- self._project_path_arg = None
239
- self._project_env_overrides_args = {}
240
- self._typer_pre_execute_commands = []
241
- self._template_context = None
242
- self._silent: bool = False
39
+ connection_context: ConnectionContext = field(default_factory=ConnectionContext)
40
+ connection_cache: OpenConnectionCache = (
41
+ _CONNECTION_CACHE # by default, use global cache
42
+ )
43
+
44
+ output_format: OutputFormat = OutputFormat.TABLE
45
+ silent: bool = False
46
+ verbose: bool = False
47
+ experimental: bool = False
48
+ enable_tracebacks: bool = True
49
+
50
+ metrics: CLIMetrics = field(default_factory=CLIMetrics)
51
+
52
+ project_path_arg: str | None = None
53
+ project_is_optional: bool = True
54
+ project_env_overrides_args: dict[str, str] = field(default_factory=dict)
55
+
56
+ # FIXME: this property only exists to help implement
57
+ # nativeapp_definition_v2_to_v1. Consider changing the way
58
+ # this calculation is provided to commands in order to remove
59
+ # this logic (then make project_definition a non-cloned @property)
60
+ override_project_definition: ProjectDefinition | None = None
61
+
62
+ _definition_manager: DefinitionManager | None = None
63
+
64
+ # which properties invalidate our current DefinitionManager?
65
+ DEFINITION_MANAGER_DEPENDENCIES = [
66
+ "project_path_arg",
67
+ "project_is_optional",
68
+ "project_env_overrides_args",
69
+ ]
243
70
 
244
71
  def reset(self):
245
72
  self.__init__()
246
73
 
247
- @property
248
- def enable_tracebacks(self) -> bool:
249
- return self._enable_tracebacks
250
-
251
- def set_enable_tracebacks(self, value: bool):
252
- self._enable_tracebacks = value
253
-
254
- @property
255
- def output_format(self) -> OutputFormat:
256
- return self._output_format
257
-
258
- def set_output_format(self, value: OutputFormat):
259
- self._output_format = value
260
-
261
- @property
262
- def verbose(self) -> bool:
263
- return self._verbose
264
-
265
- def set_verbose(self, value: bool):
266
- self._verbose = value
267
-
268
- @property
269
- def experimental(self) -> bool:
270
- return self._experimental
271
-
272
- def set_experimental(self, value: bool):
273
- self._experimental = value
274
-
275
- @property
276
- def project_definition(self) -> Optional[ProjectDefinition]:
277
- return self._project_definition
278
-
279
- def set_project_definition(self, value: ProjectDefinition):
280
- self._project_definition = value
74
+ def clone(self) -> _CliGlobalContextManager:
75
+ return replace(
76
+ self,
77
+ connection_context=self.connection_context.clone(),
78
+ project_env_overrides_args=self.project_env_overrides_args.copy(),
79
+ )
281
80
 
282
- @property
283
- def project_root(self):
284
- return self._project_root
81
+ def __setattr__(self, prop, val):
82
+ if prop in self.DEFINITION_MANAGER_DEPENDENCIES:
83
+ self._clear_definition_manager()
285
84
 
286
- def set_project_root(self, project_root: Path):
287
- self._project_root = project_root
85
+ super().__setattr__(prop, val)
288
86
 
289
87
  @property
290
- def project_path_arg(self) -> Optional[str]:
291
- return self._project_path_arg
88
+ def project_definition(self) -> ProjectDefinition | None:
89
+ if self.override_project_definition:
90
+ return self.override_project_definition
292
91
 
293
- def set_project_path_arg(self, project_path_arg: str):
294
- self._project_path_arg = project_path_arg
92
+ return self._definition_manager_or_raise().project_definition
295
93
 
296
94
  @property
297
- def project_env_overrides_args(self) -> dict[str, str]:
298
- return self._project_env_overrides_args
299
-
300
- def set_project_env_overrides_args(
301
- self, project_env_overrides_args: dict[str, str]
302
- ):
303
- self._project_env_overrides_args = project_env_overrides_args
95
+ def project_root(self) -> Path:
96
+ return Path(self._definition_manager_or_raise().project_root)
304
97
 
305
98
  @property
306
99
  def template_context(self) -> dict:
307
- return self._template_context
308
-
309
- def set_template_context(self, template_context: dict):
310
- self._template_context = template_context
311
-
312
- @property
313
- def typer_pre_execute_commands(self) -> list[Callable[[], None]]:
314
- return self._typer_pre_execute_commands
315
-
316
- def add_typer_pre_execute_commands(
317
- self, typer_pre_execute_command: Callable[[], None]
318
- ):
319
- self._typer_pre_execute_commands.append(typer_pre_execute_command)
320
-
321
- @property
322
- def connection_context(self) -> _ConnectionContext:
323
- return self._connection_context
100
+ return self._definition_manager_or_raise().template_context
324
101
 
325
102
  @property
326
103
  def connection(self) -> SnowflakeConnection:
327
- return self.connection_context.connection
328
-
329
- @property
330
- def silent(self) -> bool:
331
- return self._silent
104
+ """
105
+ Returns a connection for our configured context from the configured cache.
106
+ By default, this is the global _CONNECTION_CACHE. If a matching connection
107
+ does not already exist, creates a new connection and caches it.
108
+ """
109
+ self.connection_context.validate_and_complete()
110
+ return self.connection_cache[self.connection_context]
332
111
 
333
- def set_silent(self, value: bool):
334
- self._silent = value
112
+ def _definition_manager_or_raise(self) -> DefinitionManager:
113
+ """
114
+ (Re-)parses project definition based on project args (project_path_arg and
115
+ project_env_overrides_args). If we cannot provide a project definition
116
+ (i.e. no snowflake.yml) and require one, raises MissingConfiguration.
117
+ """
118
+ from snowflake.cli.api.project.definition_manager import DefinitionManager
119
+
120
+ # don't need to re-parse definition if we already have one
121
+ if not self._definition_manager:
122
+ dm = DefinitionManager(
123
+ self.project_path_arg,
124
+ {CONTEXT_KEY: {"env": self.project_env_overrides_args}},
125
+ )
126
+ if not dm.has_definition_file and not self.project_is_optional:
127
+ raise MissingConfiguration(
128
+ "Cannot find project definition (snowflake.yml). Please provide a path to the project or run this command in a valid project directory."
129
+ )
130
+ self._definition_manager = dm
131
+
132
+ return self._definition_manager
133
+
134
+ def _clear_definition_manager(self):
135
+ """
136
+ Force re-calculation of definition_manager and its dependent attributes
137
+ (template_context, project_definition, and project_root).
138
+ """
139
+ self._definition_manager = None
335
140
 
336
141
 
337
142
  class _CliGlobalContextAccess:
@@ -343,13 +148,17 @@ class _CliGlobalContextAccess:
343
148
  return self._manager.connection
344
149
 
345
150
  @property
346
- def connection_context(self) -> _ConnectionContext:
151
+ def connection_context(self) -> ConnectionContext:
347
152
  return self._manager.connection_context
348
153
 
349
154
  @property
350
155
  def enable_tracebacks(self) -> bool:
351
156
  return self._manager.enable_tracebacks
352
157
 
158
+ @property
159
+ def metrics(self):
160
+ return self._manager.metrics
161
+
353
162
  @property
354
163
  def output_format(self) -> OutputFormat:
355
164
  return self._manager.output_format
@@ -367,7 +176,7 @@ class _CliGlobalContextAccess:
367
176
  return self._manager.project_definition
368
177
 
369
178
  @property
370
- def project_root(self):
179
+ def project_root(self) -> Path | None:
371
180
  return self._manager.project_root
372
181
 
373
182
  @property
@@ -386,5 +195,53 @@ class _CliGlobalContextAccess:
386
195
  return self._manager.output_format == OutputFormat.JSON
387
196
 
388
197
 
389
- cli_context_manager: _CliGlobalContextManager = _CliGlobalContextManager()
390
- cli_context: _CliGlobalContextAccess = _CliGlobalContextAccess(cli_context_manager)
198
+ _CLI_CONTEXT_MANAGER: ContextVar[_CliGlobalContextManager | None] = ContextVar(
199
+ "cli_context", default=None
200
+ )
201
+
202
+
203
+ def get_cli_context_manager() -> _CliGlobalContextManager:
204
+ mgr = _CLI_CONTEXT_MANAGER.get()
205
+ if not mgr:
206
+ mgr = _CliGlobalContextManager()
207
+ _CLI_CONTEXT_MANAGER.set(mgr)
208
+ return mgr
209
+
210
+
211
+ def get_cli_context() -> _CliGlobalContextAccess:
212
+ return _CliGlobalContextAccess(get_cli_context_manager())
213
+
214
+
215
+ @contextmanager
216
+ def fork_cli_context(
217
+ connection_overrides: dict | None = None,
218
+ project_env_overrides: dict[str, str] | None = None,
219
+ project_is_optional: bool | None = None,
220
+ project_path: str | None = None,
221
+ ) -> Iterator[_CliGlobalContextAccess]:
222
+ """
223
+ Forks the global CLI context, making changes that are only visible
224
+ (e.g. via get_cli_context()) while inside this context manager.
225
+
226
+ Please note that environment variable changes are only visible through
227
+ the project definition; os.getenv / os.environ / get_env_value are not
228
+ affected by these new values.
229
+ """
230
+ old_manager = get_cli_context_manager()
231
+ new_manager = old_manager.clone()
232
+ token = _CLI_CONTEXT_MANAGER.set(new_manager)
233
+
234
+ if connection_overrides:
235
+ new_manager.connection_context.update(**connection_overrides)
236
+
237
+ if project_env_overrides:
238
+ new_manager.project_env_overrides_args.update(project_env_overrides)
239
+
240
+ if project_is_optional is not None:
241
+ new_manager.project_is_optional = project_is_optional
242
+
243
+ if project_path:
244
+ new_manager.project_path_arg = project_path
245
+
246
+ yield _CliGlobalContextAccess(new_manager)
247
+ _CLI_CONTEXT_MANAGER.reset(token)
@@ -0,0 +1,25 @@
1
+ from dataclasses import dataclass
2
+ from enum import Enum
3
+
4
+
5
+ class OnErrorType(Enum):
6
+ """
7
+ Command option values for what to do when an error occurs.
8
+ """
9
+
10
+ BREAK = "break"
11
+ CONTINUE = "continue"
12
+
13
+
14
+ @dataclass
15
+ class Variable:
16
+ """
17
+ Key-value pair dataclass, returned after parsing "key=value" command options.
18
+ """
19
+
20
+ key: str
21
+ value: str
22
+
23
+ def __init__(self, key: str, value: str):
24
+ self.key = key
25
+ self.value = value