snowflake-cli 2.8.2__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 (240) hide show
  1. snowflake/cli/__about__.py +17 -0
  2. snowflake/cli/__init__.py +13 -0
  3. snowflake/cli/api/__init__.py +48 -0
  4. snowflake/cli/api/cli_global_context.py +390 -0
  5. snowflake/cli/api/commands/__init__.py +13 -0
  6. snowflake/cli/api/commands/alias.py +23 -0
  7. snowflake/cli/api/commands/decorators.py +354 -0
  8. snowflake/cli/api/commands/execution_metadata.py +40 -0
  9. snowflake/cli/api/commands/experimental_behaviour.py +19 -0
  10. snowflake/cli/api/commands/flags.py +662 -0
  11. snowflake/cli/api/commands/project_initialisation.py +65 -0
  12. snowflake/cli/api/commands/snow_typer.py +237 -0
  13. snowflake/cli/api/commands/typer_pre_execute.py +26 -0
  14. snowflake/cli/api/config.py +348 -0
  15. snowflake/cli/api/console/__init__.py +17 -0
  16. snowflake/cli/api/console/abc.py +89 -0
  17. snowflake/cli/api/console/console.py +134 -0
  18. snowflake/cli/api/console/enum.py +17 -0
  19. snowflake/cli/api/constants.py +79 -0
  20. snowflake/cli/api/errno.py +27 -0
  21. snowflake/cli/api/exceptions.py +164 -0
  22. snowflake/cli/api/feature_flags.py +55 -0
  23. snowflake/cli/api/identifiers.py +167 -0
  24. snowflake/cli/api/output/__init__.py +13 -0
  25. snowflake/cli/api/output/formats.py +20 -0
  26. snowflake/cli/api/output/types.py +118 -0
  27. snowflake/cli/api/plugins/__init__.py +13 -0
  28. snowflake/cli/api/plugins/command/__init__.py +72 -0
  29. snowflake/cli/api/plugins/command/plugin_hook_specs.py +21 -0
  30. snowflake/cli/api/plugins/plugin_config.py +32 -0
  31. snowflake/cli/api/project/__init__.py +13 -0
  32. snowflake/cli/api/project/definition.py +84 -0
  33. snowflake/cli/api/project/definition_manager.py +134 -0
  34. snowflake/cli/api/project/errors.py +56 -0
  35. snowflake/cli/api/project/project_verification.py +23 -0
  36. snowflake/cli/api/project/schemas/__init__.py +13 -0
  37. snowflake/cli/api/project/schemas/entities/application_entity.py +44 -0
  38. snowflake/cli/api/project/schemas/entities/application_package_entity.py +66 -0
  39. snowflake/cli/api/project/schemas/entities/common.py +78 -0
  40. snowflake/cli/api/project/schemas/entities/entities.py +30 -0
  41. snowflake/cli/api/project/schemas/identifier_model.py +49 -0
  42. snowflake/cli/api/project/schemas/native_app/__init__.py +13 -0
  43. snowflake/cli/api/project/schemas/native_app/application.py +62 -0
  44. snowflake/cli/api/project/schemas/native_app/native_app.py +93 -0
  45. snowflake/cli/api/project/schemas/native_app/package.py +78 -0
  46. snowflake/cli/api/project/schemas/native_app/path_mapping.py +65 -0
  47. snowflake/cli/api/project/schemas/project_definition.py +199 -0
  48. snowflake/cli/api/project/schemas/snowpark/__init__.py +13 -0
  49. snowflake/cli/api/project/schemas/snowpark/argument.py +28 -0
  50. snowflake/cli/api/project/schemas/snowpark/callable.py +69 -0
  51. snowflake/cli/api/project/schemas/snowpark/snowpark.py +36 -0
  52. snowflake/cli/api/project/schemas/streamlit/__init__.py +13 -0
  53. snowflake/cli/api/project/schemas/streamlit/streamlit.py +46 -0
  54. snowflake/cli/api/project/schemas/template.py +77 -0
  55. snowflake/cli/api/project/schemas/updatable_model.py +194 -0
  56. snowflake/cli/api/project/util.py +261 -0
  57. snowflake/cli/api/rendering/__init__.py +13 -0
  58. snowflake/cli/api/rendering/jinja.py +112 -0
  59. snowflake/cli/api/rendering/project_definition_templates.py +39 -0
  60. snowflake/cli/api/rendering/project_templates.py +98 -0
  61. snowflake/cli/api/rendering/sql_templates.py +60 -0
  62. snowflake/cli/api/rest_api.py +172 -0
  63. snowflake/cli/api/sanitizers.py +43 -0
  64. snowflake/cli/api/secure_path.py +362 -0
  65. snowflake/cli/api/secure_utils.py +29 -0
  66. snowflake/cli/api/sql_execution.py +260 -0
  67. snowflake/cli/api/utils/__init__.py +13 -0
  68. snowflake/cli/api/utils/cursor.py +34 -0
  69. snowflake/cli/api/utils/definition_rendering.py +383 -0
  70. snowflake/cli/api/utils/dict_utils.py +73 -0
  71. snowflake/cli/api/utils/error_handling.py +23 -0
  72. snowflake/cli/api/utils/graph.py +97 -0
  73. snowflake/cli/api/utils/models.py +63 -0
  74. snowflake/cli/api/utils/naming_utils.py +13 -0
  75. snowflake/cli/api/utils/path_utils.py +36 -0
  76. snowflake/cli/api/utils/templating_functions.py +144 -0
  77. snowflake/cli/api/utils/types.py +35 -0
  78. snowflake/cli/app/__init__.py +22 -0
  79. snowflake/cli/app/__main__.py +31 -0
  80. snowflake/cli/app/api_impl/__init__.py +13 -0
  81. snowflake/cli/app/api_impl/plugin/__init__.py +13 -0
  82. snowflake/cli/app/api_impl/plugin/plugin_config_provider_impl.py +66 -0
  83. snowflake/cli/app/build_and_push.sh +8 -0
  84. snowflake/cli/app/cli_app.py +243 -0
  85. snowflake/cli/app/commands_registration/__init__.py +33 -0
  86. snowflake/cli/app/commands_registration/builtin_plugins.py +54 -0
  87. snowflake/cli/app/commands_registration/command_plugins_loader.py +169 -0
  88. snowflake/cli/app/commands_registration/commands_registration_with_callbacks.py +105 -0
  89. snowflake/cli/app/commands_registration/exception_logging.py +26 -0
  90. snowflake/cli/app/commands_registration/threadsafe.py +48 -0
  91. snowflake/cli/app/commands_registration/typer_registration.py +153 -0
  92. snowflake/cli/app/constants.py +19 -0
  93. snowflake/cli/app/dev/__init__.py +13 -0
  94. snowflake/cli/app/dev/commands_structure.py +48 -0
  95. snowflake/cli/app/dev/docs/__init__.py +13 -0
  96. snowflake/cli/app/dev/docs/commands_docs_generator.py +100 -0
  97. snowflake/cli/app/dev/docs/generator.py +35 -0
  98. snowflake/cli/app/dev/docs/project_definition_docs_generator.py +58 -0
  99. snowflake/cli/app/dev/docs/project_definition_generate_json_schema.py +227 -0
  100. snowflake/cli/app/dev/docs/template_utils.py +23 -0
  101. snowflake/cli/app/dev/docs/templates/definition_description.rst.jinja2 +38 -0
  102. snowflake/cli/app/dev/docs/templates/overview.rst.jinja2 +9 -0
  103. snowflake/cli/app/dev/docs/templates/usage.rst.jinja2 +57 -0
  104. snowflake/cli/app/dev/pycharm_remote_debug.py +46 -0
  105. snowflake/cli/app/loggers.py +199 -0
  106. snowflake/cli/app/main_typer.py +62 -0
  107. snowflake/cli/app/printing.py +181 -0
  108. snowflake/cli/app/snow_connector.py +243 -0
  109. snowflake/cli/app/telemetry.py +189 -0
  110. snowflake/cli/plugins/__init__.py +13 -0
  111. snowflake/cli/plugins/connection/__init__.py +13 -0
  112. snowflake/cli/plugins/connection/commands.py +330 -0
  113. snowflake/cli/plugins/connection/plugin_spec.py +30 -0
  114. snowflake/cli/plugins/connection/util.py +179 -0
  115. snowflake/cli/plugins/cortex/__init__.py +13 -0
  116. snowflake/cli/plugins/cortex/commands.py +327 -0
  117. snowflake/cli/plugins/cortex/constants.py +17 -0
  118. snowflake/cli/plugins/cortex/manager.py +189 -0
  119. snowflake/cli/plugins/cortex/plugin_spec.py +30 -0
  120. snowflake/cli/plugins/cortex/types.py +22 -0
  121. snowflake/cli/plugins/git/__init__.py +13 -0
  122. snowflake/cli/plugins/git/commands.py +354 -0
  123. snowflake/cli/plugins/git/manager.py +105 -0
  124. snowflake/cli/plugins/git/plugin_spec.py +30 -0
  125. snowflake/cli/plugins/init/__init__.py +13 -0
  126. snowflake/cli/plugins/init/commands.py +248 -0
  127. snowflake/cli/plugins/init/plugin_spec.py +30 -0
  128. snowflake/cli/plugins/nativeapp/__init__.py +13 -0
  129. snowflake/cli/plugins/nativeapp/artifacts.py +742 -0
  130. snowflake/cli/plugins/nativeapp/codegen/__init__.py +13 -0
  131. snowflake/cli/plugins/nativeapp/codegen/artifact_processor.py +91 -0
  132. snowflake/cli/plugins/nativeapp/codegen/compiler.py +130 -0
  133. snowflake/cli/plugins/nativeapp/codegen/sandbox.py +306 -0
  134. snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +172 -0
  135. snowflake/cli/plugins/nativeapp/codegen/setup/setup_driver.py.source +56 -0
  136. snowflake/cli/plugins/nativeapp/codegen/snowpark/callback_source.py.jinja +181 -0
  137. snowflake/cli/plugins/nativeapp/codegen/snowpark/extension_function_utils.py +217 -0
  138. snowflake/cli/plugins/nativeapp/codegen/snowpark/models.py +61 -0
  139. snowflake/cli/plugins/nativeapp/codegen/snowpark/python_processor.py +528 -0
  140. snowflake/cli/plugins/nativeapp/commands.py +439 -0
  141. snowflake/cli/plugins/nativeapp/common_flags.py +44 -0
  142. snowflake/cli/plugins/nativeapp/constants.py +27 -0
  143. snowflake/cli/plugins/nativeapp/exceptions.py +122 -0
  144. snowflake/cli/plugins/nativeapp/feature_flags.py +24 -0
  145. snowflake/cli/plugins/nativeapp/init.py +345 -0
  146. snowflake/cli/plugins/nativeapp/manager.py +823 -0
  147. snowflake/cli/plugins/nativeapp/plugin_spec.py +30 -0
  148. snowflake/cli/plugins/nativeapp/policy.py +50 -0
  149. snowflake/cli/plugins/nativeapp/project_model.py +195 -0
  150. snowflake/cli/plugins/nativeapp/run_processor.py +389 -0
  151. snowflake/cli/plugins/nativeapp/teardown_processor.py +301 -0
  152. snowflake/cli/plugins/nativeapp/utils.py +98 -0
  153. snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +135 -0
  154. snowflake/cli/plugins/nativeapp/version/__init__.py +13 -0
  155. snowflake/cli/plugins/nativeapp/version/commands.py +170 -0
  156. snowflake/cli/plugins/nativeapp/version/version_processor.py +362 -0
  157. snowflake/cli/plugins/notebook/__init__.py +13 -0
  158. snowflake/cli/plugins/notebook/commands.py +85 -0
  159. snowflake/cli/plugins/notebook/exceptions.py +20 -0
  160. snowflake/cli/plugins/notebook/manager.py +71 -0
  161. snowflake/cli/plugins/notebook/plugin_spec.py +30 -0
  162. snowflake/cli/plugins/notebook/types.py +15 -0
  163. snowflake/cli/plugins/object/__init__.py +13 -0
  164. snowflake/cli/plugins/object/command_aliases.py +95 -0
  165. snowflake/cli/plugins/object/commands.py +181 -0
  166. snowflake/cli/plugins/object/common.py +85 -0
  167. snowflake/cli/plugins/object/manager.py +97 -0
  168. snowflake/cli/plugins/object/plugin_spec.py +30 -0
  169. snowflake/cli/plugins/object_stage_deprecated/__init__.py +15 -0
  170. snowflake/cli/plugins/object_stage_deprecated/commands.py +122 -0
  171. snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +32 -0
  172. snowflake/cli/plugins/snowpark/__init__.py +13 -0
  173. snowflake/cli/plugins/snowpark/commands.py +546 -0
  174. snowflake/cli/plugins/snowpark/common.py +307 -0
  175. snowflake/cli/plugins/snowpark/manager.py +109 -0
  176. snowflake/cli/plugins/snowpark/models.py +157 -0
  177. snowflake/cli/plugins/snowpark/package/__init__.py +13 -0
  178. snowflake/cli/plugins/snowpark/package/anaconda_packages.py +233 -0
  179. snowflake/cli/plugins/snowpark/package/commands.py +256 -0
  180. snowflake/cli/plugins/snowpark/package/manager.py +44 -0
  181. snowflake/cli/plugins/snowpark/package/utils.py +26 -0
  182. snowflake/cli/plugins/snowpark/package_utils.py +354 -0
  183. snowflake/cli/plugins/snowpark/plugin_spec.py +30 -0
  184. snowflake/cli/plugins/snowpark/snowpark_package_paths.py +65 -0
  185. snowflake/cli/plugins/snowpark/snowpark_shared.py +95 -0
  186. snowflake/cli/plugins/snowpark/zipper.py +81 -0
  187. snowflake/cli/plugins/spcs/__init__.py +35 -0
  188. snowflake/cli/plugins/spcs/common.py +99 -0
  189. snowflake/cli/plugins/spcs/compute_pool/__init__.py +13 -0
  190. snowflake/cli/plugins/spcs/compute_pool/commands.py +241 -0
  191. snowflake/cli/plugins/spcs/compute_pool/manager.py +121 -0
  192. snowflake/cli/plugins/spcs/image_registry/__init__.py +13 -0
  193. snowflake/cli/plugins/spcs/image_registry/commands.py +65 -0
  194. snowflake/cli/plugins/spcs/image_registry/manager.py +105 -0
  195. snowflake/cli/plugins/spcs/image_repository/__init__.py +13 -0
  196. snowflake/cli/plugins/spcs/image_repository/commands.py +202 -0
  197. snowflake/cli/plugins/spcs/image_repository/manager.py +84 -0
  198. snowflake/cli/plugins/spcs/jobs/__init__.py +13 -0
  199. snowflake/cli/plugins/spcs/jobs/commands.py +78 -0
  200. snowflake/cli/plugins/spcs/jobs/manager.py +53 -0
  201. snowflake/cli/plugins/spcs/plugin_spec.py +30 -0
  202. snowflake/cli/plugins/spcs/services/__init__.py +13 -0
  203. snowflake/cli/plugins/spcs/services/commands.py +312 -0
  204. snowflake/cli/plugins/spcs/services/manager.py +170 -0
  205. snowflake/cli/plugins/sql/__init__.py +13 -0
  206. snowflake/cli/plugins/sql/commands.py +83 -0
  207. snowflake/cli/plugins/sql/manager.py +92 -0
  208. snowflake/cli/plugins/sql/plugin_spec.py +30 -0
  209. snowflake/cli/plugins/sql/snowsql_templating.py +28 -0
  210. snowflake/cli/plugins/stage/__init__.py +13 -0
  211. snowflake/cli/plugins/stage/commands.py +263 -0
  212. snowflake/cli/plugins/stage/diff.py +326 -0
  213. snowflake/cli/plugins/stage/manager.py +577 -0
  214. snowflake/cli/plugins/stage/md5.py +160 -0
  215. snowflake/cli/plugins/stage/plugin_spec.py +30 -0
  216. snowflake/cli/plugins/streamlit/__init__.py +13 -0
  217. snowflake/cli/plugins/streamlit/commands.py +179 -0
  218. snowflake/cli/plugins/streamlit/manager.py +222 -0
  219. snowflake/cli/plugins/streamlit/plugin_spec.py +30 -0
  220. snowflake/cli/plugins/workspace/__init__.py +13 -0
  221. snowflake/cli/plugins/workspace/commands.py +35 -0
  222. snowflake/cli/plugins/workspace/plugin_spec.py +30 -0
  223. snowflake/cli/templates/default_snowpark/.gitignore +4 -0
  224. snowflake/cli/templates/default_snowpark/app/__init__.py +0 -0
  225. snowflake/cli/templates/default_snowpark/app/common.py +2 -0
  226. snowflake/cli/templates/default_snowpark/app/functions.py +15 -0
  227. snowflake/cli/templates/default_snowpark/app/procedures.py +22 -0
  228. snowflake/cli/templates/default_snowpark/requirements.txt +1 -0
  229. snowflake/cli/templates/default_snowpark/snowflake.yml +23 -0
  230. snowflake/cli/templates/default_streamlit/.gitignore +4 -0
  231. snowflake/cli/templates/default_streamlit/common/hello.py +2 -0
  232. snowflake/cli/templates/default_streamlit/environment.yml +6 -0
  233. snowflake/cli/templates/default_streamlit/pages/my_page.py +3 -0
  234. snowflake/cli/templates/default_streamlit/snowflake.yml +10 -0
  235. snowflake/cli/templates/default_streamlit/streamlit_app.py +4 -0
  236. snowflake_cli-2.8.2.dist-info/METADATA +325 -0
  237. snowflake_cli-2.8.2.dist-info/RECORD +240 -0
  238. snowflake_cli-2.8.2.dist-info/WHEEL +4 -0
  239. snowflake_cli-2.8.2.dist-info/entry_points.txt +2 -0
  240. snowflake_cli-2.8.2.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,167 @@
1
+ # Copyright (c) 2024 Snowflake Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ import re
18
+
19
+ from click import ClickException
20
+ from snowflake.cli.api.cli_global_context import cli_context
21
+ from snowflake.cli.api.exceptions import FQNInconsistencyError, FQNNameError
22
+ from snowflake.cli.api.project.schemas.identifier_model import ObjectIdentifierBaseModel
23
+ from snowflake.cli.api.project.util import VALID_IDENTIFIER_REGEX, identifier_for_url
24
+
25
+
26
+ class FQN:
27
+ """
28
+ Class representing an identifier and supporting fully qualified names.
29
+
30
+ The instance supports builder pattern that allows updating the identifier with database and
31
+ schema from different sources. For example:
32
+
33
+ fqn = FQN.from_string("my_schema.object").using_connection(conn)
34
+ fqn = FQN.from_identifier_model(cli_context.project_definition.streamlit).using_context()
35
+ fqn = FQN.from_string("my_name").set_database("db").set_schema("foo")
36
+ """
37
+
38
+ def __init__(
39
+ self,
40
+ database: str | None,
41
+ schema: str | None,
42
+ name: str,
43
+ signature: str | None = None,
44
+ ):
45
+ self._database = database
46
+ self._schema = schema
47
+ self._name = name
48
+ self.signature = signature
49
+
50
+ @property
51
+ def database(self) -> str | None:
52
+ return self._database
53
+
54
+ @property
55
+ def schema(self) -> str | None:
56
+ return self._schema
57
+
58
+ @property
59
+ def name(self) -> str:
60
+ return self._name
61
+
62
+ @property
63
+ def prefix(self) -> str:
64
+ if self.database:
65
+ return f"{self.database}.{self.schema if self.schema else 'PUBLIC'}"
66
+ if self.schema:
67
+ return f"{self.schema}"
68
+ return ""
69
+
70
+ @property
71
+ def identifier(self) -> str:
72
+ if self.prefix:
73
+ return f"{self.prefix}.{self.name}"
74
+ return self.name
75
+
76
+ @property
77
+ def url_identifier(self) -> str:
78
+ return ".".join(identifier_for_url(part) for part in self.identifier.split("."))
79
+
80
+ @property
81
+ def sql_identifier(self) -> str:
82
+ if self.signature:
83
+ return f"IDENTIFIER('{self.identifier}'){self.signature}"
84
+ return f"IDENTIFIER('{self.identifier}')"
85
+
86
+ def __str__(self):
87
+ return self.identifier
88
+
89
+ def __eq__(self, other):
90
+ return self.identifier == other.identifier
91
+
92
+ @classmethod
93
+ def from_string(cls, identifier: str) -> "FQN":
94
+ """
95
+ Takes in an object name in the form [[database.]schema.]name. Returns a FQN instance.
96
+ """
97
+ qualifier_pattern = rf"(?:(?P<first_qualifier>{VALID_IDENTIFIER_REGEX})\.)?(?:(?P<second_qualifier>{VALID_IDENTIFIER_REGEX})\.)?(?P<name>{VALID_IDENTIFIER_REGEX})(?P<signature>\(.*\))?"
98
+ result = re.fullmatch(qualifier_pattern, identifier)
99
+
100
+ if result is None:
101
+ raise FQNNameError(identifier)
102
+
103
+ unqualified_name = result.group("name")
104
+ if result.group("second_qualifier") is not None:
105
+ database = result.group("first_qualifier")
106
+ schema = result.group("second_qualifier")
107
+ else:
108
+ database = None
109
+ schema = result.group("first_qualifier")
110
+
111
+ signature = None
112
+ if result.group("signature"):
113
+ signature = result.group("signature")
114
+ return cls(
115
+ name=unqualified_name, schema=schema, database=database, signature=signature
116
+ )
117
+
118
+ @classmethod
119
+ def from_stage(cls, stage: str) -> "FQN":
120
+ name = stage
121
+ if stage.startswith("@"):
122
+ name = stage[1:]
123
+ return cls.from_string(name)
124
+
125
+ @classmethod
126
+ def from_identifier_model(cls, model: ObjectIdentifierBaseModel) -> "FQN":
127
+ """Create an instance from object model."""
128
+ if not isinstance(model, ObjectIdentifierBaseModel):
129
+ raise ClickException(
130
+ f"Expected {type(ObjectIdentifierBaseModel)}, got {model}."
131
+ )
132
+
133
+ fqn = cls.from_string(model.name)
134
+
135
+ if fqn.database and model.database:
136
+ raise FQNInconsistencyError("database", model.name)
137
+ if fqn.schema and model.schema_name:
138
+ raise FQNInconsistencyError("schema", model.name)
139
+
140
+ return fqn.set_database(model.database).set_schema(model.schema_name)
141
+
142
+ def set_database(self, database: str | None) -> "FQN":
143
+ if database:
144
+ self._database = database
145
+ return self
146
+
147
+ def set_schema(self, schema: str | None) -> "FQN":
148
+ if schema:
149
+ self._schema = schema
150
+ return self
151
+
152
+ def set_name(self, name: str) -> "FQN":
153
+ self._name = name
154
+ return self
155
+
156
+ def using_connection(self, conn) -> "FQN":
157
+ """Update the instance with database and schema from connection."""
158
+ # Update the identifier only it if wasn't already a qualified name
159
+ if conn.database and not self.database:
160
+ self.set_database(conn.database)
161
+ if conn.schema and not self.schema:
162
+ self.set_schema(conn.schema)
163
+ return self
164
+
165
+ def using_context(self) -> "FQN":
166
+ """Update the instance with database and schema from connection in current cli context."""
167
+ return self.using_connection(cli_context.connection)
@@ -0,0 +1,13 @@
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.
@@ -0,0 +1,20 @@
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 enum import Enum
16
+
17
+
18
+ class OutputFormat(Enum):
19
+ TABLE = "TABLE"
20
+ JSON = "JSON"
@@ -0,0 +1,118 @@
1
+ # Copyright (c) 2024 Snowflake Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ import json
18
+ import typing as t
19
+
20
+ from snowflake.connector import DictCursor
21
+ from snowflake.connector.cursor import SnowflakeCursor
22
+
23
+
24
+ class CommandResult:
25
+ @property
26
+ def result(self):
27
+ raise NotImplementedError()
28
+
29
+
30
+ class ObjectResult(CommandResult):
31
+ def __init__(self, element: t.Dict):
32
+ self._element = element
33
+
34
+ @property
35
+ def result(self):
36
+ return self._element
37
+
38
+
39
+ class CollectionResult(CommandResult):
40
+ def __init__(self, elements: t.Iterable[t.Dict]):
41
+ self._elements = elements
42
+
43
+ @property
44
+ def result(self):
45
+ yield from self._elements
46
+
47
+
48
+ class MultipleResults(CommandResult):
49
+ def __init__(self, elements: t.Iterable[CommandResult] | None = None):
50
+ self._elements = elements or []
51
+
52
+ def add(self, element: CommandResult):
53
+ self._elements.append(element) # type: ignore
54
+
55
+ @property
56
+ def result(self):
57
+ return (element for element in self._elements)
58
+
59
+
60
+ class StreamResult(CommandResult):
61
+ def __init__(self, generator: t.Generator[CommandResult, None, None]):
62
+ self._generator = generator
63
+
64
+ @property
65
+ def result(self):
66
+ return self._generator
67
+
68
+
69
+ class QueryResult(CollectionResult):
70
+ def __init__(self, cursor: SnowflakeCursor | DictCursor):
71
+ self.column_names = [col.name for col in cursor.description]
72
+ super().__init__(elements=self._prepare_payload(cursor))
73
+ self._query = cursor.query
74
+
75
+ def _prepare_payload(self, cursor: SnowflakeCursor | DictCursor):
76
+ if isinstance(cursor, DictCursor):
77
+ return (k for k in cursor)
78
+ return ({k: v for k, v in zip(self.column_names, row)} for row in cursor)
79
+
80
+ @property
81
+ def query(self):
82
+ return self._query
83
+
84
+
85
+ class SingleQueryResult(ObjectResult):
86
+ def __init__(self, cursor: SnowflakeCursor):
87
+ super().__init__(element=self._prepare_payload(cursor))
88
+
89
+ def _prepare_payload(self, cursor):
90
+ results = list(QueryResult(cursor).result)
91
+ if results:
92
+ return results[0]
93
+ return None
94
+
95
+
96
+ class QueryJsonValueResult(QueryResult):
97
+ def __init__(self, cursor: SnowflakeCursor):
98
+ super().__init__(cursor)
99
+
100
+ def _prepare_payload(self, cursor):
101
+ results = list(QueryResult(cursor).result)
102
+ if results:
103
+ # Return value of the first tuple
104
+ return json.loads(list(results[0].items())[0][1])
105
+ return None
106
+
107
+
108
+ class MessageResult(CommandResult):
109
+ def __init__(self, message: str):
110
+ self._message = message
111
+
112
+ @property
113
+ def message(self):
114
+ return self._message
115
+
116
+ @property
117
+ def result(self):
118
+ return {"message": self._message}
@@ -0,0 +1,13 @@
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.
@@ -0,0 +1,72 @@
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 dataclasses import dataclass
18
+ from enum import Enum
19
+ from functools import cached_property
20
+ from typing import List
21
+
22
+ import click
23
+ import pluggy
24
+ from typer import Typer
25
+ from typer.main import get_command
26
+
27
+ SNOWCLI_COMMAND_PLUGIN_NAMESPACE = "snowflake.cli.plugin.command"
28
+
29
+ plugin_hook_spec = pluggy.HookspecMarker(SNOWCLI_COMMAND_PLUGIN_NAMESPACE)
30
+ plugin_hook_impl = pluggy.HookimplMarker(SNOWCLI_COMMAND_PLUGIN_NAMESPACE)
31
+
32
+
33
+ class CommandPath:
34
+ def __init__(self, path_segments: List[str]):
35
+ self._path_segments = tuple(path_segments)
36
+
37
+ @property
38
+ def path_segments(self) -> List[str]:
39
+ return list(self._path_segments)
40
+
41
+ def __hash__(self):
42
+ return hash(self._path_segments)
43
+
44
+ def __eq__(self, other):
45
+ return self._path_segments == other._path_segments
46
+
47
+ def __str__(self) -> str:
48
+ return "snow " + " ".join(self.path_segments)
49
+
50
+
51
+ SNOWCLI_ROOT_COMMAND_PATH = CommandPath(path_segments=[])
52
+
53
+
54
+ class CommandType(Enum):
55
+ SINGLE_COMMAND = "SINGLE_COMMAND"
56
+ COMMAND_GROUP = "COMMAND_GROUP"
57
+
58
+
59
+ @dataclass(frozen=True)
60
+ class CommandSpec:
61
+ parent_command_path: CommandPath
62
+ command_type: CommandType
63
+ typer_instance: Typer
64
+
65
+ @cached_property
66
+ def command(self) -> click.Command:
67
+ self.typer_instance._add_completion = False # noqa: SLF001
68
+ return get_command(self.typer_instance)
69
+
70
+ @cached_property
71
+ def full_command_path(self) -> CommandPath:
72
+ return CommandPath(self.parent_command_path.path_segments + [self.command.name])
@@ -0,0 +1,21 @@
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.api.plugins.command import plugin_hook_spec
16
+
17
+
18
+ @plugin_hook_spec
19
+ def command_spec():
20
+ """Command spec"""
21
+ pass
@@ -0,0 +1,32 @@
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 dataclasses import dataclass
18
+ from typing import Any, Dict, List
19
+
20
+
21
+ @dataclass
22
+ class PluginConfig:
23
+ is_plugin_enabled: bool
24
+ internal_config: Dict[str, Any]
25
+
26
+
27
+ class PluginConfigProvider:
28
+ def get_enabled_plugin_names(self) -> List[str]:
29
+ raise NotImplementedError()
30
+
31
+ def get_config(self, plugin_name: str) -> PluginConfig:
32
+ raise NotImplementedError()
@@ -0,0 +1,13 @@
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.
@@ -0,0 +1,84 @@
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, Optional
19
+
20
+ import yaml
21
+ from snowflake.cli.api.cli_global_context import cli_context
22
+ from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB
23
+ from snowflake.cli.api.project.schemas.project_definition import (
24
+ ProjectProperties,
25
+ )
26
+ from snowflake.cli.api.project.util import (
27
+ append_to_identifier,
28
+ get_env_username,
29
+ sanitize_identifier,
30
+ to_identifier,
31
+ )
32
+ from snowflake.cli.api.secure_path import SecurePath
33
+ from snowflake.cli.api.utils.definition_rendering import render_definition_template
34
+ from snowflake.cli.api.utils.dict_utils import deep_merge_dicts
35
+ from snowflake.cli.api.utils.types import Context, Definition
36
+
37
+ DEFAULT_USERNAME = "unknown_user"
38
+
39
+
40
+ def _get_merged_definitions(paths: List[Path]) -> Optional[Definition]:
41
+ spaths: List[SecurePath] = [SecurePath(p) for p in paths]
42
+ if len(spaths) == 0:
43
+ return None
44
+
45
+ with spaths[0].open("r", read_file_limit_mb=DEFAULT_SIZE_LIMIT_MB) as base_yml:
46
+ definition = yaml.load(base_yml.read(), Loader=yaml.loader.BaseLoader) or {}
47
+
48
+ for override_path in spaths[1:]:
49
+ with override_path.open(
50
+ "r", read_file_limit_mb=DEFAULT_SIZE_LIMIT_MB
51
+ ) as override_yml:
52
+ overrides = (
53
+ yaml.load(override_yml.read(), Loader=yaml.loader.BaseLoader) or {}
54
+ )
55
+ deep_merge_dicts(definition, overrides)
56
+
57
+ return definition
58
+
59
+
60
+ def load_project(
61
+ paths: List[Path], context_overrides: Optional[Context] = None
62
+ ) -> ProjectProperties:
63
+ """
64
+ Loads project definition, optionally overriding values. Definition values
65
+ are merged in left-to-right order (increasing precedence).
66
+ Templating is also applied after the merging process.
67
+ """
68
+ merged_definitions = _get_merged_definitions(paths)
69
+ return render_definition_template(merged_definitions, context_overrides or {})
70
+
71
+
72
+ def default_app_package(project_name: str):
73
+ user = sanitize_identifier(get_env_username() or DEFAULT_USERNAME).lower()
74
+ return append_to_identifier(to_identifier(project_name), f"_pkg_{user}")
75
+
76
+
77
+ def default_role():
78
+ conn = cli_context.connection
79
+ return conn.role
80
+
81
+
82
+ def default_application(project_name: str):
83
+ user = sanitize_identifier(get_env_username() or DEFAULT_USERNAME).lower()
84
+ return append_to_identifier(to_identifier(project_name), f"_{user}")
@@ -0,0 +1,134 @@
1
+ # Copyright (c) 2024 Snowflake Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ import functools
18
+ import os
19
+ from pathlib import Path
20
+ from typing import List, Optional
21
+
22
+ from snowflake.cli.api.project.definition import ProjectProperties, load_project
23
+ from snowflake.cli.api.project.schemas.project_definition import ProjectDefinitionV1
24
+ from snowflake.cli.api.utils.types import Context
25
+
26
+
27
+ def _compat_is_mount(path: Path):
28
+ try:
29
+ return path.is_mount()
30
+ except NotImplementedError:
31
+ # If we can't figure out if path is mount then let's assume it is
32
+ # Windows support added in Python 3.12
33
+ return True
34
+
35
+
36
+ class DefinitionManager:
37
+ BASE_DEFINITION_FILENAME = "snowflake.yml"
38
+ USER_DEFINITION_FILENAME = "snowflake.local.yml"
39
+
40
+ project_root: Path
41
+ _project_config_paths: List[Path]
42
+
43
+ def __init__(
44
+ self,
45
+ project_arg: Optional[str] = None,
46
+ context_overrides: Optional[Context] = None,
47
+ ) -> None:
48
+ project_root = Path(
49
+ os.path.abspath(project_arg) if project_arg else os.getcwd()
50
+ )
51
+
52
+ self.project_root = project_root
53
+ self._project_config_paths = self._find_definition_files(self.project_root)
54
+ self._context_overrides = context_overrides
55
+
56
+ @functools.cached_property
57
+ def has_definition_file(self):
58
+ return len(self._project_config_paths) > 0
59
+
60
+ @staticmethod
61
+ def _find_definition_files(project_root: Path) -> List[Path]:
62
+ base_config_file_path = DefinitionManager._base_definition_file_if_available(
63
+ project_root
64
+ )
65
+ user_config_file_path = DefinitionManager._user_definition_file_if_available(
66
+ project_root
67
+ )
68
+
69
+ definition_files: List[Path] = []
70
+ if base_config_file_path:
71
+ definition_files.append(base_config_file_path)
72
+ if user_config_file_path:
73
+ definition_files.append(user_config_file_path)
74
+
75
+ return definition_files
76
+
77
+ @staticmethod
78
+ def find_project_root(search_path: Path) -> Optional[Path]:
79
+ """
80
+ Recurse up the directory tree from the given search path until we find
81
+ a directory that contains a snowflake.yml file. We'll stop if we cross
82
+ a filesystem boundary or hit the user's HOME directory.
83
+ """
84
+ current_path = search_path
85
+ starting_mount = _compat_is_mount(search_path)
86
+ while current_path:
87
+ if (
88
+ _compat_is_mount(current_path) != starting_mount
89
+ or current_path.parent == current_path
90
+ or current_path == Path.home()
91
+ ):
92
+ return None
93
+
94
+ if (
95
+ DefinitionManager._base_definition_file_if_available(current_path)
96
+ is not None
97
+ ):
98
+ # found snowflake.yml, end the search here
99
+ return current_path
100
+
101
+ current_path = current_path.parent
102
+
103
+ return None
104
+
105
+ @staticmethod
106
+ def _definition_if_available(filename, project_path: Path) -> Optional[Path]:
107
+ file_path = Path(project_path) / filename
108
+ if file_path.is_file():
109
+ return file_path
110
+ return None
111
+
112
+ @staticmethod
113
+ def _base_definition_file_if_available(project_path: Path) -> Optional[Path]:
114
+ return DefinitionManager._definition_if_available(
115
+ DefinitionManager.BASE_DEFINITION_FILENAME, project_path
116
+ )
117
+
118
+ @staticmethod
119
+ def _user_definition_file_if_available(project_path: Path) -> Optional[Path]:
120
+ return DefinitionManager._definition_if_available(
121
+ DefinitionManager.USER_DEFINITION_FILENAME, project_path
122
+ )
123
+
124
+ @functools.cached_property
125
+ def _project_properties(self) -> ProjectProperties:
126
+ return load_project(self._project_config_paths, self._context_overrides)
127
+
128
+ @functools.cached_property
129
+ def project_definition(self) -> ProjectDefinitionV1:
130
+ return self._project_properties.project_definition
131
+
132
+ @functools.cached_property
133
+ def template_context(self) -> Context:
134
+ return self._project_properties.project_context