snowflake-cli-labs 2.8.1__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 +11 -7
  27. snowflake/cli/{plugins → _plugins}/git/manager.py +55 -9
  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 +2 -2
  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 +3 -2
  59. snowflake/cli/{plugins → _plugins}/notebook/manager.py +5 -5
  60. snowflake/cli/{plugins/nativeapp → _plugins/notebook}/plugin_spec.py +1 -1
  61. snowflake/cli/{plugins → _plugins}/object/command_aliases.py +4 -4
  62. snowflake/cli/{plugins → _plugins}/object/commands.py +4 -5
  63. snowflake/cli/{plugins → _plugins}/object/manager.py +36 -15
  64. snowflake/cli/{plugins → _plugins}/object/plugin_spec.py +1 -1
  65. snowflake/cli/_plugins/snowpark/commands.py +450 -0
  66. snowflake/cli/_plugins/snowpark/common.py +268 -0
  67. snowflake/cli/{plugins → _plugins}/snowpark/models.py +0 -7
  68. snowflake/cli/{plugins → _plugins}/snowpark/package/anaconda_packages.py +2 -36
  69. snowflake/cli/{plugins → _plugins}/snowpark/package/commands.py +13 -74
  70. snowflake/cli/{plugins → _plugins}/snowpark/package/manager.py +2 -2
  71. snowflake/cli/{plugins → _plugins}/snowpark/package_utils.py +5 -5
  72. snowflake/cli/_plugins/snowpark/plugin_spec.py +30 -0
  73. snowflake/cli/_plugins/snowpark/snowpark_entity.py +29 -0
  74. snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +173 -0
  75. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +109 -0
  76. snowflake/cli/{plugins → _plugins}/snowpark/snowpark_shared.py +0 -36
  77. snowflake/cli/{plugins → _plugins}/snowpark/zipper.py +16 -8
  78. snowflake/cli/{plugins → _plugins}/spcs/__init__.py +5 -7
  79. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/commands.py +8 -8
  80. snowflake/cli/{plugins → _plugins}/spcs/compute_pool/manager.py +3 -3
  81. snowflake/cli/{plugins → _plugins}/spcs/image_registry/commands.py +3 -3
  82. snowflake/cli/{plugins → _plugins}/spcs/image_repository/commands.py +6 -6
  83. snowflake/cli/{plugins → _plugins}/spcs/image_repository/manager.py +1 -1
  84. snowflake/cli/{plugins → _plugins}/spcs/plugin_spec.py +1 -1
  85. snowflake/cli/{plugins → _plugins}/spcs/services/commands.py +44 -11
  86. snowflake/cli/{plugins → _plugins}/spcs/services/manager.py +43 -5
  87. snowflake/cli/{plugins → _plugins}/sql/commands.py +20 -17
  88. snowflake/cli/{plugins → _plugins}/sql/manager.py +1 -1
  89. snowflake/cli/{plugins → _plugins}/sql/plugin_spec.py +1 -1
  90. snowflake/cli/{plugins → _plugins}/stage/commands.py +15 -14
  91. snowflake/cli/{plugins → _plugins}/stage/diff.py +1 -47
  92. snowflake/cli/{plugins → _plugins}/stage/manager.py +12 -7
  93. snowflake/cli/{plugins → _plugins}/stage/plugin_spec.py +1 -1
  94. snowflake/cli/_plugins/stage/utils.py +54 -0
  95. snowflake/cli/{plugins → _plugins}/streamlit/commands.py +64 -48
  96. snowflake/cli/{plugins → _plugins}/streamlit/manager.py +67 -69
  97. snowflake/cli/_plugins/streamlit/plugin_spec.py +30 -0
  98. snowflake/cli/_plugins/streamlit/streamlit_entity.py +12 -0
  99. snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +66 -0
  100. snowflake/cli/_plugins/workspace/action_context.py +18 -0
  101. snowflake/cli/_plugins/workspace/commands.py +306 -0
  102. snowflake/cli/_plugins/workspace/manager.py +74 -0
  103. snowflake/cli/_plugins/workspace/plugin_spec.py +30 -0
  104. snowflake/cli/api/cli_global_context.py +152 -295
  105. snowflake/cli/api/commands/common.py +25 -0
  106. snowflake/cli/api/commands/decorators.py +19 -4
  107. snowflake/cli/api/commands/experimental_behaviour.py +2 -3
  108. snowflake/cli/api/commands/flags.py +127 -228
  109. snowflake/cli/api/commands/overrideable_parameter.py +143 -0
  110. snowflake/cli/api/commands/snow_typer.py +21 -11
  111. snowflake/cli/api/commands/utils.py +18 -0
  112. snowflake/cli/api/config.py +44 -12
  113. snowflake/cli/api/connections.py +216 -0
  114. snowflake/cli/api/console/abc.py +8 -3
  115. snowflake/cli/api/constants.py +11 -0
  116. snowflake/cli/api/entities/common.py +56 -0
  117. snowflake/cli/api/entities/utils.py +370 -0
  118. snowflake/cli/api/errno.py +1 -0
  119. snowflake/cli/api/exceptions.py +31 -5
  120. snowflake/cli/api/feature_flags.py +0 -1
  121. snowflake/cli/api/identifiers.py +28 -5
  122. snowflake/cli/api/metrics.py +92 -0
  123. snowflake/cli/api/project/definition.py +48 -6
  124. snowflake/cli/api/project/definition_conversion.py +400 -0
  125. snowflake/cli/api/project/definition_manager.py +16 -5
  126. snowflake/cli/api/project/project_verification.py +3 -3
  127. snowflake/cli/api/project/schemas/entities/common.py +91 -16
  128. snowflake/cli/api/project/schemas/entities/entities.py +37 -6
  129. snowflake/cli/api/project/schemas/project_definition.py +180 -49
  130. snowflake/cli/api/project/schemas/updatable_model.py +11 -3
  131. snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
  132. snowflake/cli/api/project/schemas/{identifier_model.py → v1/identifier_model.py} +3 -1
  133. snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
  134. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/application.py +8 -9
  135. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/native_app.py +4 -4
  136. snowflake/cli/api/project/schemas/{native_app → v1/native_app}/package.py +7 -1
  137. snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
  138. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/callable.py +2 -2
  139. snowflake/cli/api/project/schemas/{snowpark → v1/snowpark}/snowpark.py +2 -2
  140. snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
  141. snowflake/cli/api/project/schemas/{streamlit → v1/streamlit}/streamlit.py +2 -1
  142. snowflake/cli/api/project/util.py +23 -6
  143. snowflake/cli/api/rendering/jinja.py +14 -8
  144. snowflake/cli/api/rendering/project_definition_templates.py +5 -1
  145. snowflake/cli/api/rendering/sql_templates.py +56 -11
  146. snowflake/cli/api/rest_api.py +11 -5
  147. snowflake/cli/api/secure_path.py +16 -18
  148. snowflake/cli/api/secure_utils.py +90 -1
  149. snowflake/cli/api/sql_execution.py +43 -23
  150. snowflake/cli/api/utils/definition_rendering.py +45 -13
  151. {snowflake_cli_labs-2.8.1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/METADATA +20 -18
  152. snowflake_cli_labs-3.0.0.dist-info/RECORD +242 -0
  153. snowflake_cli_labs-3.0.0.dist-info/entry_points.txt +2 -0
  154. snowflake/cli/api/commands/project_initialisation.py +0 -65
  155. snowflake/cli/api/commands/typer_pre_execute.py +0 -26
  156. snowflake/cli/api/project/schemas/entities/application_entity.py +0 -44
  157. snowflake/cli/api/project/schemas/entities/application_package_entity.py +0 -66
  158. snowflake/cli/app/build_and_push.sh +0 -8
  159. snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -172
  160. snowflake/cli/plugins/nativeapp/init.py +0 -345
  161. snowflake/cli/plugins/nativeapp/manager.py +0 -823
  162. snowflake/cli/plugins/nativeapp/run_processor.py +0 -389
  163. snowflake/cli/plugins/nativeapp/teardown_processor.py +0 -301
  164. snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +0 -135
  165. snowflake/cli/plugins/nativeapp/version/version_processor.py +0 -362
  166. snowflake/cli/plugins/object_stage_deprecated/__init__.py +0 -15
  167. snowflake/cli/plugins/object_stage_deprecated/commands.py +0 -122
  168. snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +0 -32
  169. snowflake/cli/plugins/snowpark/commands.py +0 -546
  170. snowflake/cli/plugins/snowpark/common.py +0 -307
  171. snowflake/cli/plugins/snowpark/manager.py +0 -109
  172. snowflake/cli/plugins/snowpark/plugin_spec.py +0 -30
  173. snowflake/cli/plugins/snowpark/snowpark_package_paths.py +0 -65
  174. snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
  175. snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
  176. snowflake/cli/plugins/streamlit/__init__.py +0 -13
  177. snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
  178. snowflake/cli/plugins/workspace/__init__.py +0 -13
  179. snowflake/cli/plugins/workspace/commands.py +0 -35
  180. snowflake/cli/plugins/workspace/plugin_spec.py +0 -30
  181. snowflake/cli/templates/default_snowpark/.gitignore +0 -4
  182. snowflake/cli/templates/default_snowpark/app/common.py +0 -2
  183. snowflake/cli/templates/default_snowpark/app/functions.py +0 -15
  184. snowflake/cli/templates/default_snowpark/app/procedures.py +0 -22
  185. snowflake/cli/templates/default_snowpark/requirements.txt +0 -1
  186. snowflake/cli/templates/default_snowpark/snowflake.yml +0 -23
  187. snowflake/cli/templates/default_streamlit/.gitignore +0 -4
  188. snowflake/cli/templates/default_streamlit/common/hello.py +0 -2
  189. snowflake/cli/templates/default_streamlit/environment.yml +0 -6
  190. snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -3
  191. snowflake/cli/templates/default_streamlit/snowflake.yml +0 -10
  192. snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -4
  193. snowflake_cli_labs-2.8.1.dist-info/RECORD +0 -240
  194. snowflake_cli_labs-2.8.1.dist-info/entry_points.txt +0 -2
  195. /snowflake/cli/{app → _app}/__init__.py +0 -0
  196. /snowflake/cli/{api/project/schemas/native_app → _app/api_impl}/__init__.py +0 -0
  197. /snowflake/cli/{api/project/schemas/snowpark → _app/api_impl/plugin}/__init__.py +0 -0
  198. /snowflake/cli/{app → _app}/api_impl/plugin/plugin_config_provider_impl.py +0 -0
  199. /snowflake/cli/{app → _app}/commands_registration/__init__.py +0 -0
  200. /snowflake/cli/{app → _app}/commands_registration/threadsafe.py +0 -0
  201. /snowflake/cli/{app → _app}/constants.py +0 -0
  202. /snowflake/cli/{api/project/schemas/streamlit → _app/dev}/__init__.py +0 -0
  203. /snowflake/cli/{app → _app}/dev/commands_structure.py +0 -0
  204. /snowflake/cli/{app/api_impl → _app/dev/docs}/__init__.py +0 -0
  205. /snowflake/cli/{app → _app}/dev/docs/project_definition_generate_json_schema.py +0 -0
  206. /snowflake/cli/{app → _app}/dev/docs/template_utils.py +0 -0
  207. /snowflake/cli/{app → _app}/dev/docs/templates/definition_description.rst.jinja2 +0 -0
  208. /snowflake/cli/{app → _app}/dev/docs/templates/overview.rst.jinja2 +0 -0
  209. /snowflake/cli/{app → _app}/dev/pycharm_remote_debug.py +0 -0
  210. /snowflake/cli/{app → _app}/loggers.py +0 -0
  211. /snowflake/cli/{app/api_impl/plugin → _plugins}/__init__.py +0 -0
  212. /snowflake/cli/{app/dev → _plugins/connection}/__init__.py +0 -0
  213. /snowflake/cli/{app/dev/docs → _plugins/cortex}/__init__.py +0 -0
  214. /snowflake/cli/{plugins → _plugins}/cortex/types.py +0 -0
  215. /snowflake/cli/{plugins → _plugins/git}/__init__.py +0 -0
  216. /snowflake/cli/{plugins/connection → _plugins/helpers}/__init__.py +0 -0
  217. /snowflake/cli/{plugins/cortex → _plugins/init}/__init__.py +0 -0
  218. /snowflake/cli/{plugins/git → _plugins/nativeapp}/__init__.py +0 -0
  219. /snowflake/cli/{plugins/init → _plugins/nativeapp/codegen}/__init__.py +0 -0
  220. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/sandbox.py +0 -0
  221. /snowflake/cli/{plugins → _plugins}/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -0
  222. /snowflake/cli/{plugins → _plugins}/nativeapp/constants.py +0 -0
  223. /snowflake/cli/{templates/default_snowpark/app → _plugins/nativeapp/entities}/__init__.py +0 -0
  224. /snowflake/cli/{plugins → _plugins}/nativeapp/feature_flags.py +0 -0
  225. /snowflake/cli/{plugins → _plugins}/nativeapp/utils.py +0 -0
  226. /snowflake/cli/{plugins/nativeapp → _plugins/nativeapp/version}/__init__.py +0 -0
  227. /snowflake/cli/{plugins/nativeapp/codegen → _plugins/notebook}/__init__.py +0 -0
  228. /snowflake/cli/{plugins → _plugins}/notebook/exceptions.py +0 -0
  229. /snowflake/cli/{plugins → _plugins}/notebook/types.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.1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/WHEEL +0 -0
  251. {snowflake_cli_labs-2.8.1.dist-info → snowflake_cli_labs-3.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,173 @@
1
+ # Copyright (c) 2024 Snowflake Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ from pathlib import Path
18
+ from typing import List, Literal, Optional, Union
19
+
20
+ from pydantic import Field, field_validator
21
+ from snowflake.cli.api.identifiers import FQN
22
+ from snowflake.cli.api.project.schemas.entities.common import (
23
+ EntityModelBase,
24
+ ExternalAccessBaseModel,
25
+ ImportsBaseModel,
26
+ )
27
+ from snowflake.cli.api.project.schemas.updatable_model import (
28
+ DiscriminatorField,
29
+ UpdatableModel,
30
+ )
31
+ from snowflake.cli.api.project.schemas.v1.snowpark.argument import Argument
32
+
33
+
34
+ class PathMapping(UpdatableModel):
35
+ class Config:
36
+ frozen = True
37
+
38
+ src: Path = Field(title="Source path (relative to project root)", default=None)
39
+
40
+ dest: Optional[str] = Field(
41
+ title="Destination path on stage",
42
+ description="Paths are relative to stage root; paths ending with a slash indicate that the destination is a directory which source files should be copied into.",
43
+ default=None,
44
+ )
45
+
46
+
47
+ class SnowparkEntityModel(EntityModelBase, ExternalAccessBaseModel, ImportsBaseModel):
48
+ handler: str = Field(
49
+ title="Function’s or procedure’s implementation of the object inside source module",
50
+ examples=["functions.hello_function"],
51
+ )
52
+ returns: str = Field(
53
+ title="Type of the result"
54
+ ) # TODO: again, consider Literal/Enum
55
+ signature: Union[str, List[Argument]] = Field(
56
+ title="The signature parameter describes consecutive arguments passed to the object"
57
+ )
58
+ runtime: Optional[Union[str, float]] = Field(
59
+ title="Python version to use when executing ", default=None
60
+ )
61
+ stage: str = Field(title="Stage in which artifacts will be stored")
62
+ artifacts: List[Union[PathMapping, str]] = Field(title="List of required sources")
63
+
64
+ @field_validator("artifacts")
65
+ @classmethod
66
+ def _convert_artifacts(cls, artifacts: Union[dict, str]):
67
+ _artifacts = []
68
+ for artefact in artifacts:
69
+ if isinstance(artefact, PathMapping):
70
+ _artifacts.append(artefact)
71
+ else:
72
+ _artifacts.append(PathMapping(src=artefact))
73
+ return _artifacts
74
+
75
+ @field_validator("runtime")
76
+ @classmethod
77
+ def convert_runtime(cls, runtime_input: Union[str, float]) -> str:
78
+ if isinstance(runtime_input, float):
79
+ return str(runtime_input)
80
+ return runtime_input
81
+
82
+ @field_validator("artifacts")
83
+ @classmethod
84
+ def validate_artifacts(cls, artifacts: List[Path]) -> List[Path]:
85
+ for artefact in artifacts:
86
+ if "*" in str(artefact):
87
+ raise ValueError("Glob patterns not supported for Snowpark artifacts.")
88
+ return artifacts
89
+
90
+ @property
91
+ def udf_sproc_identifier(self) -> UdfSprocIdentifier:
92
+ return UdfSprocIdentifier.from_definition(self)
93
+
94
+
95
+ class ProcedureEntityModel(SnowparkEntityModel):
96
+ type: Literal["procedure"] = DiscriminatorField() # noqa: A003
97
+ execute_as_caller: Optional[bool] = Field(
98
+ title="Determine whether the procedure is executed with the privileges of "
99
+ "the owner (you) or with the privileges of the caller",
100
+ default=False,
101
+ )
102
+
103
+
104
+ class FunctionEntityModel(SnowparkEntityModel):
105
+ type: Literal["function"] = DiscriminatorField() # noqa: A003
106
+
107
+
108
+ class UdfSprocIdentifier:
109
+ def __init__(self, identifier: FQN, arg_names, arg_types, arg_defaults):
110
+ self._identifier = identifier
111
+ self._arg_names = arg_names
112
+ self._arg_types = arg_types
113
+ self._arg_defaults = arg_defaults
114
+
115
+ def _identifier_from_signature(self, sig: List[str], for_sql: bool = False):
116
+ signature = self._comma_join(sig)
117
+ id_ = self._identifier.sql_identifier if for_sql else self._identifier
118
+ return f"{id_}({signature})"
119
+
120
+ @staticmethod
121
+ def _comma_join(*args):
122
+ return ", ".join(*args)
123
+
124
+ @property
125
+ def identifier_with_arg_names(self):
126
+ return self._identifier_from_signature(self._arg_names)
127
+
128
+ @property
129
+ def identifier_with_arg_types(self):
130
+ return self._identifier_from_signature(self._arg_types)
131
+
132
+ @property
133
+ def identifier_with_arg_names_types(self):
134
+ sig = [f"{n} {t}" for n, t in zip(self._arg_names, self._arg_types)]
135
+ return self._identifier_from_signature(sig)
136
+
137
+ @property
138
+ def identifier_with_arg_names_types_defaults(self):
139
+ return self._identifier_from_signature(self._full_signature())
140
+
141
+ def _is_signature_type_a_string(self, sig_type: str) -> bool:
142
+ return sig_type.lower() in ["string", "varchar"]
143
+
144
+ def _full_signature(self):
145
+ sig = []
146
+ for name, _type, _default in zip(
147
+ self._arg_names, self._arg_types, self._arg_defaults
148
+ ):
149
+ s = f"{name} {_type}"
150
+ if _default:
151
+ if self._is_signature_type_a_string(_type):
152
+ _default = f"'{_default}'"
153
+ s += f" default {_default}"
154
+ sig.append(s)
155
+ return sig
156
+
157
+ @property
158
+ def identifier_for_sql(self):
159
+ return self._identifier_from_signature(self._full_signature(), for_sql=True)
160
+
161
+ @classmethod
162
+ def from_definition(cls, udf_sproc: SnowparkEntityModel):
163
+ names = []
164
+ types = []
165
+ defaults = []
166
+ if udf_sproc.signature and udf_sproc.signature != "null":
167
+ for arg in udf_sproc.signature:
168
+ names.append(arg.name) # type:ignore
169
+ types.append(arg.arg_type) # type:ignore
170
+ defaults.append(arg.default) # type:ignore
171
+
172
+ identifier = udf_sproc.fqn.using_context()
173
+ return cls(identifier, names, types, defaults)
@@ -0,0 +1,109 @@
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
+ from __future__ import annotations
15
+
16
+ from dataclasses import dataclass
17
+ from pathlib import Path, PurePosixPath
18
+
19
+ from snowflake.cli._plugins.snowpark.snowpark_entity_model import PathMapping
20
+ from snowflake.cli._plugins.snowpark.zipper import zip_dir
21
+ from snowflake.cli.api.console import cli_console
22
+ from snowflake.cli.api.constants import DEPLOYMENT_STAGE
23
+ from snowflake.cli.api.identifiers import FQN
24
+ from snowflake.cli.api.secure_path import SecurePath
25
+
26
+
27
+ @dataclass
28
+ class SnowparkProjectPaths:
29
+ """
30
+ This class represents allows you to manage files paths related to given project.
31
+ """
32
+
33
+ project_root: Path
34
+
35
+ def path_relative_to_root(self, artifact_path: Path) -> Path:
36
+ if artifact_path.is_absolute():
37
+ return artifact_path
38
+ return (self.project_root / artifact_path).resolve()
39
+
40
+ def get_artefact_dto(self, artifact_path: PathMapping) -> Artefact:
41
+ return Artefact(
42
+ dest=artifact_path.dest,
43
+ path=self.path_relative_to_root(artifact_path.src),
44
+ )
45
+
46
+ def get_dependencies_artefact(self) -> Artefact:
47
+ return Artefact(dest=None, path=self.dependencies)
48
+
49
+ @property
50
+ def snowflake_requirements(self) -> SecurePath:
51
+ return SecurePath(
52
+ self.path_relative_to_root(Path("requirements.snowflake.txt"))
53
+ )
54
+
55
+ @property
56
+ def requirements(self) -> SecurePath:
57
+ return SecurePath(self.path_relative_to_root(Path("requirements.txt")))
58
+
59
+ @property
60
+ def dependencies(self) -> Path:
61
+ return self.path_relative_to_root(Path("dependencies.zip"))
62
+
63
+
64
+ @dataclass(unsafe_hash=True)
65
+ class Artefact:
66
+ """Helper for getting paths related to given artefact."""
67
+
68
+ path: Path
69
+ dest: str | None = None
70
+
71
+ @property
72
+ def _artefact_name(self) -> str:
73
+ if self.path.is_dir():
74
+ return self.path.stem + ".zip"
75
+ return self.path.name
76
+
77
+ @property
78
+ def post_build_path(self) -> Path:
79
+ """
80
+ Returns post-build artefact path. Directories are mapped to corresponding .zip files.
81
+ """
82
+ return self.path.parent / self._artefact_name
83
+
84
+ def upload_path(self, stage: FQN | str | None) -> str:
85
+ """
86
+ Path on stage to which the artefact should be uploaded.
87
+ """
88
+ stage = stage or DEPLOYMENT_STAGE
89
+ if isinstance(stage, str):
90
+ stage = FQN.from_stage(stage).using_context()
91
+
92
+ stage_path = PurePosixPath(f"@{stage}")
93
+ if self.dest:
94
+ stage_path = stage_path / self.dest
95
+ return str(stage_path) + "/"
96
+
97
+ def import_path(self, stage: FQN | str | None) -> str:
98
+ """Path for UDF/sproc imports clause."""
99
+ return self.upload_path(stage) + self._artefact_name
100
+
101
+ def build(self) -> None:
102
+ """Build the artefact. Applies only to directories. Files are untouched."""
103
+ if not self.path.is_dir():
104
+ return
105
+ cli_console.step(f"Creating: {self.post_build_path.name}")
106
+ zip_dir(
107
+ source=self.path,
108
+ dest_zip=self.post_build_path,
109
+ )
@@ -14,33 +14,7 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- import click
18
17
  import typer
19
- from snowflake.cli.api.commands.flags import (
20
- deprecated_flag_callback,
21
- deprecated_flag_callback_enum,
22
- )
23
- from snowflake.cli.plugins.snowpark.models import YesNoAsk
24
-
25
-
26
- def deprecated_allow_native_libraries_option(old_flag_name: str):
27
- return typer.Option(
28
- YesNoAsk.NO.value,
29
- old_flag_name,
30
- help="Allows native libraries, when using packages installed through PIP",
31
- hidden=True,
32
- callback=deprecated_flag_callback_enum(
33
- f"{old_flag_name} flag is deprecated. Use --allow-shared-libraries flag instead."
34
- ),
35
- )
36
-
37
-
38
- def resolve_allow_shared_libraries_yes_no_ask(allow_shared_libraries: YesNoAsk) -> bool:
39
- if allow_shared_libraries == YesNoAsk.ASK:
40
- return click.confirm("Continue with package installation?", default=False)
41
- else:
42
- return allow_shared_libraries == YesNoAsk.YES
43
-
44
18
 
45
19
  AllowSharedLibrariesOption: bool = typer.Option(
46
20
  False,
@@ -48,16 +22,6 @@ AllowSharedLibrariesOption: bool = typer.Option(
48
22
  help="Allows shared (.so) libraries, when using packages installed through PIP.",
49
23
  )
50
24
 
51
- DeprecatedCheckAnacondaForPyPiDependencies: bool = typer.Option(
52
- True,
53
- "--check-anaconda-for-pypi-deps/--no-check-anaconda-for-pypi-deps",
54
- "-a",
55
- help="""Checks if any of missing Anaconda packages dependencies can be imported directly from Anaconda. Valid values include: `true`, `false`, Default: `true`.""",
56
- hidden=True,
57
- callback=deprecated_flag_callback(
58
- "--check-anaconda-for-pypi-deps flag is deprecated. Use --ignore-anaconda flag instead."
59
- ),
60
- )
61
25
 
62
26
  IgnoreAnacondaOption: bool = typer.Option(
63
27
  False,
@@ -17,7 +17,7 @@ from __future__ import annotations
17
17
  import fnmatch
18
18
  import logging
19
19
  from pathlib import Path
20
- from typing import Iterator, Literal
20
+ from typing import Dict, List, Literal
21
21
  from zipfile import ZIP_DEFLATED, ZipFile
22
22
 
23
23
  log = logging.getLogger(__name__)
@@ -59,16 +59,24 @@ def add_file_to_existing_zip(zip_file: str, file: str):
59
59
 
60
60
 
61
61
  def zip_dir(
62
- source: Path, dest_zip: Path, mode: Literal["r", "w", "x", "a"] = "w"
62
+ source: Path | List[Path],
63
+ dest_zip: Path,
64
+ mode: Literal["r", "w", "x", "a"] = "w",
63
65
  ) -> None:
64
- files_to_pack: Iterator[Path] = filter(
65
- _to_be_zipped, map(lambda f: f.absolute(), source.glob("**/*"))
66
- )
66
+
67
+ if isinstance(source, Path):
68
+ source = [source]
69
+
70
+ files_to_pack: Dict[Path, List[Path]] = {
71
+ src: list(filter(_to_be_zipped, (f.absolute() for f in src.glob("**/*"))))
72
+ for src in source
73
+ }
67
74
 
68
75
  with ZipFile(dest_zip, mode, ZIP_DEFLATED, allowZip64=True) as package_zip:
69
- for file in files_to_pack:
70
- log.debug("Adding %s to %s", file, dest_zip)
71
- package_zip.write(file, arcname=file.relative_to(source.absolute()))
76
+ for src, files in files_to_pack.items():
77
+ for file in files:
78
+ log.debug("Adding %s to %s", file, dest_zip)
79
+ package_zip.write(file, arcname=file.relative_to(src))
72
80
 
73
81
 
74
82
  def _to_be_zipped(file: Path) -> bool:
@@ -12,16 +12,15 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
16
- from snowflake.cli.plugins.spcs.compute_pool.commands import (
15
+ from snowflake.cli._plugins.spcs.compute_pool.commands import (
17
16
  app as compute_pools_app,
18
17
  )
19
- from snowflake.cli.plugins.spcs.image_registry.commands import app as registry_app
20
- from snowflake.cli.plugins.spcs.image_repository.commands import (
18
+ from snowflake.cli._plugins.spcs.image_registry.commands import app as registry_app
19
+ from snowflake.cli._plugins.spcs.image_repository.commands import (
21
20
  app as image_repository_app,
22
21
  )
23
- from snowflake.cli.plugins.spcs.jobs.commands import app as jobs_app
24
- from snowflake.cli.plugins.spcs.services.commands import app as services_app
22
+ from snowflake.cli._plugins.spcs.services.commands import app as services_app
23
+ from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
25
24
 
26
25
  app = SnowTyperFactory(
27
26
  name="spcs",
@@ -30,6 +29,5 @@ app = SnowTyperFactory(
30
29
 
31
30
  app.add_typer(compute_pools_app)
32
31
  app.add_typer(services_app)
33
- app.add_typer(jobs_app)
34
32
  app.add_typer(registry_app)
35
33
  app.add_typer(image_repository_app)
@@ -18,6 +18,14 @@ from typing import Optional
18
18
 
19
19
  import typer
20
20
  from click import ClickException
21
+ from snowflake.cli._plugins.object.command_aliases import (
22
+ add_object_command_aliases,
23
+ )
24
+ from snowflake.cli._plugins.object.common import CommentOption
25
+ from snowflake.cli._plugins.spcs.common import (
26
+ validate_and_set_instances,
27
+ )
28
+ from snowflake.cli._plugins.spcs.compute_pool.manager import ComputePoolManager
21
29
  from snowflake.cli.api.commands.flags import (
22
30
  IfNotExistsOption,
23
31
  OverrideableOption,
@@ -29,14 +37,6 @@ from snowflake.cli.api.constants import ObjectType
29
37
  from snowflake.cli.api.identifiers import FQN
30
38
  from snowflake.cli.api.output.types import CommandResult, SingleQueryResult
31
39
  from snowflake.cli.api.project.util import is_valid_object_name
32
- from snowflake.cli.plugins.object.command_aliases import (
33
- add_object_command_aliases,
34
- )
35
- from snowflake.cli.plugins.object.common import CommentOption
36
- from snowflake.cli.plugins.spcs.common import (
37
- validate_and_set_instances,
38
- )
39
- from snowflake.cli.plugins.spcs.compute_pool.manager import ComputePoolManager
40
40
 
41
41
  app = SnowTyperFactory(
42
42
  name="compute-pool",
@@ -16,13 +16,13 @@ from __future__ import annotations
16
16
 
17
17
  from typing import List, Optional
18
18
 
19
- from snowflake.cli.api.constants import ObjectType
20
- from snowflake.cli.api.sql_execution import SqlExecutionMixin
21
- from snowflake.cli.plugins.spcs.common import (
19
+ from snowflake.cli._plugins.spcs.common import (
22
20
  NoPropertiesProvidedError,
23
21
  handle_object_already_exists,
24
22
  strip_empty_lines,
25
23
  )
24
+ from snowflake.cli.api.constants import ObjectType
25
+ from snowflake.cli.api.sql_execution import SqlExecutionMixin
26
26
  from snowflake.connector.cursor import SnowflakeCursor
27
27
  from snowflake.connector.errors import ProgrammingError
28
28
 
@@ -12,11 +12,11 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
16
- from snowflake.cli.api.output.types import MessageResult, ObjectResult
17
- from snowflake.cli.plugins.spcs.image_registry.manager import (
15
+ from snowflake.cli._plugins.spcs.image_registry.manager import (
18
16
  RegistryManager,
19
17
  )
18
+ from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
19
+ from snowflake.cli.api.output.types import MessageResult, ObjectResult
20
20
 
21
21
  app = SnowTyperFactory(
22
22
  name="image-registry",
@@ -20,6 +20,12 @@ from typing import Optional
20
20
  import requests
21
21
  import typer
22
22
  from click import ClickException
23
+ from snowflake.cli._plugins.object.command_aliases import (
24
+ add_object_command_aliases,
25
+ scope_option,
26
+ )
27
+ from snowflake.cli._plugins.spcs.image_registry.manager import RegistryManager
28
+ from snowflake.cli._plugins.spcs.image_repository.manager import ImageRepositoryManager
23
29
  from snowflake.cli.api.commands.flags import (
24
30
  IfNotExistsOption,
25
31
  ReplaceOption,
@@ -36,12 +42,6 @@ from snowflake.cli.api.output.types import (
36
42
  SingleQueryResult,
37
43
  )
38
44
  from snowflake.cli.api.project.util import is_valid_object_name
39
- from snowflake.cli.plugins.object.command_aliases import (
40
- add_object_command_aliases,
41
- scope_option,
42
- )
43
- from snowflake.cli.plugins.spcs.image_registry.manager import RegistryManager
44
- from snowflake.cli.plugins.spcs.image_repository.manager import ImageRepositoryManager
45
45
 
46
46
  app = SnowTyperFactory(
47
47
  name="image-repository",
@@ -14,10 +14,10 @@
14
14
 
15
15
  from urllib.parse import urlparse
16
16
 
17
+ from snowflake.cli._plugins.spcs.common import handle_object_already_exists
17
18
  from snowflake.cli.api.constants import ObjectType
18
19
  from snowflake.cli.api.identifiers import FQN
19
20
  from snowflake.cli.api.sql_execution import SqlExecutionMixin
20
- from snowflake.cli.plugins.spcs.common import handle_object_already_exists
21
21
  from snowflake.connector.errors import ProgrammingError
22
22
 
23
23
 
@@ -12,13 +12,13 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from snowflake.cli._plugins.spcs import app
15
16
  from snowflake.cli.api.plugins.command import (
16
17
  SNOWCLI_ROOT_COMMAND_PATH,
17
18
  CommandSpec,
18
19
  CommandType,
19
20
  plugin_hook_impl,
20
21
  )
21
- from snowflake.cli.plugins.spcs import app
22
22
 
23
23
 
24
24
  @plugin_hook_impl
@@ -20,6 +20,16 @@ from typing import List, Optional
20
20
 
21
21
  import typer
22
22
  from click import ClickException
23
+ from snowflake.cli._plugins.object.command_aliases import (
24
+ add_object_command_aliases,
25
+ scope_option,
26
+ )
27
+ from snowflake.cli._plugins.object.common import CommentOption, Tag, TagOption
28
+ from snowflake.cli._plugins.spcs.common import (
29
+ print_log_lines,
30
+ validate_and_set_instances,
31
+ )
32
+ from snowflake.cli._plugins.spcs.services.manager import ServiceManager
23
33
  from snowflake.cli.api.commands.flags import (
24
34
  IfNotExistsOption,
25
35
  OverrideableOption,
@@ -36,16 +46,6 @@ from snowflake.cli.api.output.types import (
36
46
  SingleQueryResult,
37
47
  )
38
48
  from snowflake.cli.api.project.util import is_valid_object_name
39
- from snowflake.cli.plugins.object.command_aliases import (
40
- add_object_command_aliases,
41
- scope_option,
42
- )
43
- from snowflake.cli.plugins.object.common import CommentOption, Tag, TagOption
44
- from snowflake.cli.plugins.spcs.common import (
45
- print_log_lines,
46
- validate_and_set_instances,
47
- )
48
- from snowflake.cli.plugins.spcs.services.manager import ServiceManager
49
49
 
50
50
  app = SnowTyperFactory(
51
51
  name="service",
@@ -63,7 +63,7 @@ def _service_name_callback(name: FQN) -> FQN:
63
63
 
64
64
 
65
65
  ServiceNameArgument = identifier_argument(
66
- sf_object="service pool",
66
+ sf_object="service",
67
67
  example="my_service",
68
68
  callback=_service_name_callback,
69
69
  )
@@ -161,6 +161,39 @@ def create(
161
161
  return SingleQueryResult(cursor)
162
162
 
163
163
 
164
+ @app.command(requires_connection=True)
165
+ def execute_job(
166
+ name: FQN = ServiceNameArgument,
167
+ compute_pool: str = typer.Option(
168
+ ...,
169
+ "--compute-pool",
170
+ help="Compute pool to run the job service on.",
171
+ show_default=False,
172
+ ),
173
+ spec_path: Path = SpecPathOption,
174
+ external_access_integrations: Optional[List[str]] = typer.Option(
175
+ None,
176
+ "--eai-name",
177
+ help="Identifies External Access Integrations(EAI) that the job service can access. This option may be specified multiple times for multiple EAIs.",
178
+ ),
179
+ query_warehouse: Optional[str] = QueryWarehouseOption(),
180
+ comment: Optional[str] = CommentOption(help=_COMMENT_HELP),
181
+ **options,
182
+ ) -> CommandResult:
183
+ """
184
+ Creates and executes a job service in the current schema.
185
+ """
186
+ cursor = ServiceManager().execute_job(
187
+ job_service_name=name.identifier,
188
+ compute_pool=compute_pool,
189
+ spec_path=spec_path,
190
+ external_access_integrations=external_access_integrations,
191
+ query_warehouse=query_warehouse,
192
+ comment=comment,
193
+ )
194
+ return SingleQueryResult(cursor)
195
+
196
+
164
197
  @app.command(requires_connection=True)
165
198
  def status(name: FQN = ServiceNameArgument, **options) -> CommandResult:
166
199
  """
@@ -19,15 +19,15 @@ from pathlib import Path
19
19
  from typing import List, Optional
20
20
 
21
21
  import yaml
22
- from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB, ObjectType
23
- from snowflake.cli.api.secure_path import SecurePath
24
- from snowflake.cli.api.sql_execution import SqlExecutionMixin
25
- from snowflake.cli.plugins.object.common import Tag
26
- from snowflake.cli.plugins.spcs.common import (
22
+ from snowflake.cli._plugins.object.common import Tag
23
+ from snowflake.cli._plugins.spcs.common import (
27
24
  NoPropertiesProvidedError,
28
25
  handle_object_already_exists,
29
26
  strip_empty_lines,
30
27
  )
28
+ from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB, ObjectType
29
+ from snowflake.cli.api.secure_path import SecurePath
30
+ from snowflake.cli.api.sql_execution import SqlExecutionMixin
31
31
  from snowflake.connector.cursor import SnowflakeCursor
32
32
  from snowflake.connector.errors import ProgrammingError
33
33
 
@@ -85,6 +85,44 @@ class ServiceManager(SqlExecutionMixin):
85
85
  except ProgrammingError as e:
86
86
  handle_object_already_exists(e, ObjectType.SERVICE, service_name)
87
87
 
88
+ def execute_job(
89
+ self,
90
+ job_service_name: str,
91
+ compute_pool: str,
92
+ spec_path: Path,
93
+ external_access_integrations: Optional[List[str]],
94
+ query_warehouse: Optional[str],
95
+ comment: Optional[str],
96
+ ) -> SnowflakeCursor:
97
+ spec = self._read_yaml(spec_path)
98
+ query = f"""\
99
+ EXECUTE JOB SERVICE
100
+ IN COMPUTE POOL {compute_pool}
101
+ FROM SPECIFICATION $$
102
+ {spec}
103
+ $$
104
+ NAME = {job_service_name}
105
+ """.splitlines()
106
+
107
+ if external_access_integrations:
108
+ external_access_integration_list = ",".join(
109
+ f"{e}" for e in external_access_integrations
110
+ )
111
+ query.append(
112
+ f"EXTERNAL_ACCESS_INTEGRATIONS = ({external_access_integration_list})"
113
+ )
114
+
115
+ if query_warehouse:
116
+ query.append(f"QUERY_WAREHOUSE = {query_warehouse}")
117
+
118
+ if comment:
119
+ query.append(f"COMMENT = {comment}")
120
+
121
+ try:
122
+ return self._execute_query(strip_empty_lines(query))
123
+ except ProgrammingError as e:
124
+ handle_object_already_exists(e, ObjectType.SERVICE, job_service_name)
125
+
88
126
  def _read_yaml(self, path: Path) -> str:
89
127
  # TODO(aivanou): Add validation towards schema
90
128
  with SecurePath(path).open("r", read_file_limit_mb=DEFAULT_SIZE_LIMIT_MB) as fh: