snowflake-cli-labs 3.0.0rc4__py3-none-any.whl → 3.0.1__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 (244) hide show
  1. README.md +21 -0
  2. {snowflake_cli_labs-3.0.0rc4.dist-info → snowflake_cli_labs-3.0.1.dist-info}/METADATA +6 -96
  3. snowflake_cli_labs-3.0.1.dist-info/RECORD +5 -0
  4. snowflake/cli/__about__.py +0 -17
  5. snowflake/cli/__init__.py +0 -13
  6. snowflake/cli/_app/__init__.py +0 -22
  7. snowflake/cli/_app/__main__.py +0 -31
  8. snowflake/cli/_app/api_impl/__init__.py +0 -13
  9. snowflake/cli/_app/api_impl/plugin/__init__.py +0 -13
  10. snowflake/cli/_app/api_impl/plugin/plugin_config_provider_impl.py +0 -66
  11. snowflake/cli/_app/cli_app.py +0 -252
  12. snowflake/cli/_app/commands_registration/__init__.py +0 -33
  13. snowflake/cli/_app/commands_registration/builtin_plugins.py +0 -50
  14. snowflake/cli/_app/commands_registration/command_plugins_loader.py +0 -169
  15. snowflake/cli/_app/commands_registration/commands_registration_with_callbacks.py +0 -105
  16. snowflake/cli/_app/commands_registration/exception_logging.py +0 -26
  17. snowflake/cli/_app/commands_registration/threadsafe.py +0 -48
  18. snowflake/cli/_app/commands_registration/typer_registration.py +0 -153
  19. snowflake/cli/_app/constants.py +0 -19
  20. snowflake/cli/_app/dev/__init__.py +0 -13
  21. snowflake/cli/_app/dev/commands_structure.py +0 -48
  22. snowflake/cli/_app/dev/docs/__init__.py +0 -13
  23. snowflake/cli/_app/dev/docs/commands_docs_generator.py +0 -118
  24. snowflake/cli/_app/dev/docs/generator.py +0 -35
  25. snowflake/cli/_app/dev/docs/project_definition_docs_generator.py +0 -58
  26. snowflake/cli/_app/dev/docs/project_definition_generate_json_schema.py +0 -227
  27. snowflake/cli/_app/dev/docs/template_utils.py +0 -23
  28. snowflake/cli/_app/dev/docs/templates/definition_description.rst.jinja2 +0 -38
  29. snowflake/cli/_app/dev/docs/templates/overview.rst.jinja2 +0 -9
  30. snowflake/cli/_app/dev/docs/templates/usage.rst.jinja2 +0 -67
  31. snowflake/cli/_app/dev/pycharm_remote_debug.py +0 -46
  32. snowflake/cli/_app/loggers.py +0 -199
  33. snowflake/cli/_app/main_typer.py +0 -62
  34. snowflake/cli/_app/printing.py +0 -181
  35. snowflake/cli/_app/secret.py +0 -9
  36. snowflake/cli/_app/snow_connector.py +0 -309
  37. snowflake/cli/_app/telemetry.py +0 -220
  38. snowflake/cli/_app/version_check.py +0 -74
  39. snowflake/cli/_plugins/__init__.py +0 -13
  40. snowflake/cli/_plugins/connection/__init__.py +0 -13
  41. snowflake/cli/_plugins/connection/commands.py +0 -353
  42. snowflake/cli/_plugins/connection/plugin_spec.py +0 -30
  43. snowflake/cli/_plugins/connection/util.py +0 -195
  44. snowflake/cli/_plugins/cortex/__init__.py +0 -13
  45. snowflake/cli/_plugins/cortex/commands.py +0 -332
  46. snowflake/cli/_plugins/cortex/constants.py +0 -17
  47. snowflake/cli/_plugins/cortex/manager.py +0 -189
  48. snowflake/cli/_plugins/cortex/plugin_spec.py +0 -30
  49. snowflake/cli/_plugins/cortex/types.py +0 -22
  50. snowflake/cli/_plugins/git/__init__.py +0 -13
  51. snowflake/cli/_plugins/git/commands.py +0 -358
  52. snowflake/cli/_plugins/git/manager.py +0 -151
  53. snowflake/cli/_plugins/git/plugin_spec.py +0 -30
  54. snowflake/cli/_plugins/helpers/__init__.py +0 -13
  55. snowflake/cli/_plugins/helpers/commands.py +0 -61
  56. snowflake/cli/_plugins/helpers/plugin_spec.py +0 -30
  57. snowflake/cli/_plugins/init/__init__.py +0 -13
  58. snowflake/cli/_plugins/init/commands.py +0 -248
  59. snowflake/cli/_plugins/init/plugin_spec.py +0 -30
  60. snowflake/cli/_plugins/nativeapp/__init__.py +0 -13
  61. snowflake/cli/_plugins/nativeapp/artifacts.py +0 -757
  62. snowflake/cli/_plugins/nativeapp/bundle_context.py +0 -31
  63. snowflake/cli/_plugins/nativeapp/codegen/__init__.py +0 -13
  64. snowflake/cli/_plugins/nativeapp/codegen/artifact_processor.py +0 -91
  65. snowflake/cli/_plugins/nativeapp/codegen/compiler.py +0 -149
  66. snowflake/cli/_plugins/nativeapp/codegen/sandbox.py +0 -306
  67. snowflake/cli/_plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -249
  68. snowflake/cli/_plugins/nativeapp/codegen/setup/setup_driver.py.source +0 -59
  69. snowflake/cli/_plugins/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -181
  70. snowflake/cli/_plugins/nativeapp/codegen/snowpark/extension_function_utils.py +0 -217
  71. snowflake/cli/_plugins/nativeapp/codegen/snowpark/models.py +0 -61
  72. snowflake/cli/_plugins/nativeapp/codegen/snowpark/python_processor.py +0 -523
  73. snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py +0 -114
  74. snowflake/cli/_plugins/nativeapp/commands.py +0 -559
  75. snowflake/cli/_plugins/nativeapp/common_flags.py +0 -44
  76. snowflake/cli/_plugins/nativeapp/constants.py +0 -27
  77. snowflake/cli/_plugins/nativeapp/entities/__init__.py +0 -0
  78. snowflake/cli/_plugins/nativeapp/entities/application.py +0 -878
  79. snowflake/cli/_plugins/nativeapp/entities/application_package.py +0 -1392
  80. snowflake/cli/_plugins/nativeapp/exceptions.py +0 -113
  81. snowflake/cli/_plugins/nativeapp/feature_flags.py +0 -24
  82. snowflake/cli/_plugins/nativeapp/manager.py +0 -415
  83. snowflake/cli/_plugins/nativeapp/plugin_spec.py +0 -30
  84. snowflake/cli/_plugins/nativeapp/policy.py +0 -53
  85. snowflake/cli/_plugins/nativeapp/project_model.py +0 -211
  86. snowflake/cli/_plugins/nativeapp/run_processor.py +0 -184
  87. snowflake/cli/_plugins/nativeapp/same_account_install_method.py +0 -70
  88. snowflake/cli/_plugins/nativeapp/teardown_processor.py +0 -70
  89. snowflake/cli/_plugins/nativeapp/utils.py +0 -98
  90. snowflake/cli/_plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +0 -262
  91. snowflake/cli/_plugins/nativeapp/version/__init__.py +0 -13
  92. snowflake/cli/_plugins/nativeapp/version/commands.py +0 -141
  93. snowflake/cli/_plugins/nativeapp/version/version_processor.py +0 -98
  94. snowflake/cli/_plugins/notebook/__init__.py +0 -13
  95. snowflake/cli/_plugins/notebook/commands.py +0 -86
  96. snowflake/cli/_plugins/notebook/exceptions.py +0 -20
  97. snowflake/cli/_plugins/notebook/manager.py +0 -71
  98. snowflake/cli/_plugins/notebook/plugin_spec.py +0 -30
  99. snowflake/cli/_plugins/notebook/types.py +0 -15
  100. snowflake/cli/_plugins/object/__init__.py +0 -13
  101. snowflake/cli/_plugins/object/command_aliases.py +0 -95
  102. snowflake/cli/_plugins/object/commands.py +0 -180
  103. snowflake/cli/_plugins/object/common.py +0 -85
  104. snowflake/cli/_plugins/object/manager.py +0 -118
  105. snowflake/cli/_plugins/object/plugin_spec.py +0 -30
  106. snowflake/cli/_plugins/snowpark/__init__.py +0 -13
  107. snowflake/cli/_plugins/snowpark/commands.py +0 -450
  108. snowflake/cli/_plugins/snowpark/common.py +0 -268
  109. snowflake/cli/_plugins/snowpark/models.py +0 -150
  110. snowflake/cli/_plugins/snowpark/package/__init__.py +0 -13
  111. snowflake/cli/_plugins/snowpark/package/anaconda_packages.py +0 -199
  112. snowflake/cli/_plugins/snowpark/package/commands.py +0 -195
  113. snowflake/cli/_plugins/snowpark/package/manager.py +0 -44
  114. snowflake/cli/_plugins/snowpark/package/utils.py +0 -26
  115. snowflake/cli/_plugins/snowpark/package_utils.py +0 -354
  116. snowflake/cli/_plugins/snowpark/plugin_spec.py +0 -30
  117. snowflake/cli/_plugins/snowpark/snowpark_entity.py +0 -29
  118. snowflake/cli/_plugins/snowpark/snowpark_entity_model.py +0 -173
  119. snowflake/cli/_plugins/snowpark/snowpark_project_paths.py +0 -109
  120. snowflake/cli/_plugins/snowpark/snowpark_shared.py +0 -59
  121. snowflake/cli/_plugins/snowpark/zipper.py +0 -89
  122. snowflake/cli/_plugins/spcs/__init__.py +0 -33
  123. snowflake/cli/_plugins/spcs/common.py +0 -99
  124. snowflake/cli/_plugins/spcs/compute_pool/__init__.py +0 -13
  125. snowflake/cli/_plugins/spcs/compute_pool/commands.py +0 -241
  126. snowflake/cli/_plugins/spcs/compute_pool/manager.py +0 -121
  127. snowflake/cli/_plugins/spcs/image_registry/__init__.py +0 -13
  128. snowflake/cli/_plugins/spcs/image_registry/commands.py +0 -65
  129. snowflake/cli/_plugins/spcs/image_registry/manager.py +0 -105
  130. snowflake/cli/_plugins/spcs/image_repository/__init__.py +0 -13
  131. snowflake/cli/_plugins/spcs/image_repository/commands.py +0 -202
  132. snowflake/cli/_plugins/spcs/image_repository/manager.py +0 -84
  133. snowflake/cli/_plugins/spcs/plugin_spec.py +0 -30
  134. snowflake/cli/_plugins/spcs/services/__init__.py +0 -13
  135. snowflake/cli/_plugins/spcs/services/commands.py +0 -345
  136. snowflake/cli/_plugins/spcs/services/manager.py +0 -208
  137. snowflake/cli/_plugins/sql/__init__.py +0 -13
  138. snowflake/cli/_plugins/sql/commands.py +0 -86
  139. snowflake/cli/_plugins/sql/manager.py +0 -92
  140. snowflake/cli/_plugins/sql/plugin_spec.py +0 -30
  141. snowflake/cli/_plugins/sql/snowsql_templating.py +0 -28
  142. snowflake/cli/_plugins/stage/__init__.py +0 -13
  143. snowflake/cli/_plugins/stage/commands.py +0 -264
  144. snowflake/cli/_plugins/stage/diff.py +0 -280
  145. snowflake/cli/_plugins/stage/manager.py +0 -582
  146. snowflake/cli/_plugins/stage/md5.py +0 -160
  147. snowflake/cli/_plugins/stage/plugin_spec.py +0 -30
  148. snowflake/cli/_plugins/stage/utils.py +0 -54
  149. snowflake/cli/_plugins/streamlit/__init__.py +0 -13
  150. snowflake/cli/_plugins/streamlit/commands.py +0 -195
  151. snowflake/cli/_plugins/streamlit/manager.py +0 -220
  152. snowflake/cli/_plugins/streamlit/plugin_spec.py +0 -30
  153. snowflake/cli/_plugins/streamlit/streamlit_entity.py +0 -12
  154. snowflake/cli/_plugins/streamlit/streamlit_entity_model.py +0 -66
  155. snowflake/cli/_plugins/workspace/__init__.py +0 -13
  156. snowflake/cli/_plugins/workspace/action_context.py +0 -18
  157. snowflake/cli/_plugins/workspace/commands.py +0 -306
  158. snowflake/cli/_plugins/workspace/manager.py +0 -74
  159. snowflake/cli/_plugins/workspace/plugin_spec.py +0 -30
  160. snowflake/cli/api/__init__.py +0 -48
  161. snowflake/cli/api/cli_global_context.py +0 -247
  162. snowflake/cli/api/commands/__init__.py +0 -13
  163. snowflake/cli/api/commands/alias.py +0 -23
  164. snowflake/cli/api/commands/common.py +0 -25
  165. snowflake/cli/api/commands/decorators.py +0 -369
  166. snowflake/cli/api/commands/execution_metadata.py +0 -40
  167. snowflake/cli/api/commands/experimental_behaviour.py +0 -18
  168. snowflake/cli/api/commands/flags.py +0 -561
  169. snowflake/cli/api/commands/overrideable_parameter.py +0 -143
  170. snowflake/cli/api/commands/snow_typer.py +0 -247
  171. snowflake/cli/api/commands/utils.py +0 -18
  172. snowflake/cli/api/config.py +0 -380
  173. snowflake/cli/api/connections.py +0 -216
  174. snowflake/cli/api/console/__init__.py +0 -17
  175. snowflake/cli/api/console/abc.py +0 -94
  176. snowflake/cli/api/console/console.py +0 -134
  177. snowflake/cli/api/console/enum.py +0 -17
  178. snowflake/cli/api/constants.py +0 -90
  179. snowflake/cli/api/entities/common.py +0 -56
  180. snowflake/cli/api/entities/utils.py +0 -370
  181. snowflake/cli/api/errno.py +0 -28
  182. snowflake/cli/api/exceptions.py +0 -190
  183. snowflake/cli/api/feature_flags.py +0 -54
  184. snowflake/cli/api/identifiers.py +0 -190
  185. snowflake/cli/api/metrics.py +0 -92
  186. snowflake/cli/api/output/__init__.py +0 -13
  187. snowflake/cli/api/output/formats.py +0 -20
  188. snowflake/cli/api/output/types.py +0 -118
  189. snowflake/cli/api/plugins/__init__.py +0 -13
  190. snowflake/cli/api/plugins/command/__init__.py +0 -72
  191. snowflake/cli/api/plugins/command/plugin_hook_specs.py +0 -21
  192. snowflake/cli/api/plugins/plugin_config.py +0 -32
  193. snowflake/cli/api/project/__init__.py +0 -13
  194. snowflake/cli/api/project/definition.py +0 -126
  195. snowflake/cli/api/project/definition_conversion.py +0 -395
  196. snowflake/cli/api/project/definition_manager.py +0 -145
  197. snowflake/cli/api/project/errors.py +0 -56
  198. snowflake/cli/api/project/project_verification.py +0 -23
  199. snowflake/cli/api/project/schemas/__init__.py +0 -13
  200. snowflake/cli/api/project/schemas/entities/__init__.py +0 -13
  201. snowflake/cli/api/project/schemas/entities/common.py +0 -153
  202. snowflake/cli/api/project/schemas/entities/entities.py +0 -61
  203. snowflake/cli/api/project/schemas/project_definition.py +0 -330
  204. snowflake/cli/api/project/schemas/template.py +0 -77
  205. snowflake/cli/api/project/schemas/updatable_model.py +0 -202
  206. snowflake/cli/api/project/schemas/v1/__init__.py +0 -0
  207. snowflake/cli/api/project/schemas/v1/identifier_model.py +0 -51
  208. snowflake/cli/api/project/schemas/v1/native_app/__init__.py +0 -0
  209. snowflake/cli/api/project/schemas/v1/native_app/application.py +0 -61
  210. snowflake/cli/api/project/schemas/v1/native_app/native_app.py +0 -93
  211. snowflake/cli/api/project/schemas/v1/native_app/package.py +0 -84
  212. snowflake/cli/api/project/schemas/v1/native_app/path_mapping.py +0 -65
  213. snowflake/cli/api/project/schemas/v1/snowpark/__init__.py +0 -0
  214. snowflake/cli/api/project/schemas/v1/snowpark/argument.py +0 -28
  215. snowflake/cli/api/project/schemas/v1/snowpark/callable.py +0 -69
  216. snowflake/cli/api/project/schemas/v1/snowpark/snowpark.py +0 -36
  217. snowflake/cli/api/project/schemas/v1/streamlit/__init__.py +0 -0
  218. snowflake/cli/api/project/schemas/v1/streamlit/streamlit.py +0 -47
  219. snowflake/cli/api/project/util.py +0 -278
  220. snowflake/cli/api/rendering/__init__.py +0 -13
  221. snowflake/cli/api/rendering/jinja.py +0 -118
  222. snowflake/cli/api/rendering/project_definition_templates.py +0 -43
  223. snowflake/cli/api/rendering/project_templates.py +0 -98
  224. snowflake/cli/api/rendering/sql_templates.py +0 -105
  225. snowflake/cli/api/rest_api.py +0 -178
  226. snowflake/cli/api/sanitizers.py +0 -43
  227. snowflake/cli/api/secure_path.py +0 -360
  228. snowflake/cli/api/secure_utils.py +0 -118
  229. snowflake/cli/api/sql_execution.py +0 -280
  230. snowflake/cli/api/utils/__init__.py +0 -13
  231. snowflake/cli/api/utils/cursor.py +0 -34
  232. snowflake/cli/api/utils/definition_rendering.py +0 -415
  233. snowflake/cli/api/utils/dict_utils.py +0 -73
  234. snowflake/cli/api/utils/error_handling.py +0 -23
  235. snowflake/cli/api/utils/graph.py +0 -97
  236. snowflake/cli/api/utils/models.py +0 -63
  237. snowflake/cli/api/utils/naming_utils.py +0 -13
  238. snowflake/cli/api/utils/path_utils.py +0 -36
  239. snowflake/cli/api/utils/templating_functions.py +0 -144
  240. snowflake/cli/api/utils/types.py +0 -35
  241. snowflake_cli_labs-3.0.0rc4.dist-info/RECORD +0 -242
  242. snowflake_cli_labs-3.0.0rc4.dist-info/entry_points.txt +0 -2
  243. {snowflake_cli_labs-3.0.0rc4.dist-info → snowflake_cli_labs-3.0.1.dist-info}/WHEEL +0 -0
  244. {snowflake_cli_labs-3.0.0rc4.dist-info → snowflake_cli_labs-3.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,278 +0,0 @@
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 codecs
18
- import os
19
- import re
20
- from typing import List, Optional
21
- from urllib.parse import quote
22
-
23
- IDENTIFIER = r'((?:"[^"]*(?:""[^"]*)*")|(?:[A-Za-z_][\w$]{0,254}))'
24
- IDENTIFIER_NO_LENGTH = r'((?:"[^"]*(?:""[^"]*)*")|(?:[A-Za-z_][\w$]*))'
25
- DB_SCHEMA_AND_NAME = f"{IDENTIFIER}[.]{IDENTIFIER}[.]{IDENTIFIER}"
26
- SCHEMA_AND_NAME = f"{IDENTIFIER}[.]{IDENTIFIER}"
27
- GLOB_REGEX = r"^[a-zA-Z0-9_\-./*?**\p{L}\p{N}]+$"
28
- RELATIVE_PATH = r"^[^/][\p{L}\p{N}_\-.][^/]*$"
29
-
30
- SINGLE_QUOTED_STRING_LITERAL_REGEX = r"'((?:\\.|''|[^'\n])+?)'"
31
-
32
- # See https://docs.snowflake.com/en/sql-reference/identifiers-syntax for identifier syntax
33
- UNQUOTED_IDENTIFIER_REGEX = r"([a-zA-Z_])([a-zA-Z0-9_$]{0,254})"
34
- QUOTED_IDENTIFIER_REGEX = r'"((""|[^"]){0,255})"'
35
- VALID_IDENTIFIER_REGEX = f"(?:{UNQUOTED_IDENTIFIER_REGEX}|{QUOTED_IDENTIFIER_REGEX})"
36
-
37
- # An env var that is used to suffix the names of some account-level resources
38
- TEST_RESOURCE_SUFFIX_VAR = "SNOWFLAKE_CLI_TEST_RESOURCE_SUFFIX"
39
-
40
-
41
- def encode_uri_component(s: str) -> str:
42
- """
43
- Implementation of JavaScript's encodeURIComponent.
44
- """
45
- return quote(s, safe="!~*'()")
46
-
47
-
48
- def sanitize_identifier(input_: str):
49
- """
50
- Removes characters that cannot be used in an unquoted identifier.
51
- If the identifier does not start with a letter or underscore, prefix it with an underscore.
52
- Limits the identifier to 255 characters.
53
- """
54
- value = re.sub(r"[^a-zA-Z0-9_$]", "", f"{input_}")
55
-
56
- # if it does not start with a letter or underscore, prefix it with an underscore
57
- if not value or not re.match(r"[a-zA-Z_]", value[0]):
58
- value = f"_{value}"
59
-
60
- # limit it to 255 characters
61
- return value[:255]
62
-
63
-
64
- def is_valid_unquoted_identifier(identifier: str) -> bool:
65
- """
66
- Determines whether the provided identifier is a valid Snowflake unquoted identifier.
67
- """
68
- return re.fullmatch(UNQUOTED_IDENTIFIER_REGEX, identifier) is not None
69
-
70
-
71
- def is_valid_quoted_identifier(identifier: str) -> bool:
72
- """
73
- Determines whether the provided identifier is a valid Snowflake quoted identifier.
74
- """
75
- return re.fullmatch(QUOTED_IDENTIFIER_REGEX, identifier) is not None
76
-
77
-
78
- def is_valid_identifier(identifier: str) -> bool:
79
- """
80
- Determines whether the provided identifier is a valid Snowflake quoted or unquoted identifier.
81
- """
82
- return is_valid_unquoted_identifier(identifier) or is_valid_quoted_identifier(
83
- identifier
84
- )
85
-
86
-
87
- def is_valid_object_name(name: str, max_depth=2, allow_quoted=True) -> bool:
88
- """
89
- Determines whether the given identifier is a valid object name in the form <name>, <schema>.<name>, or <database>.<schema>.<name>.
90
- Max_depth determines how many valid identifiers are allowed. For example, account level objects would have a max depth of 0
91
- because they cannot be qualified by a database or schema, just the single identifier.
92
- """
93
- if max_depth < 0:
94
- raise ValueError("max_depth must be non-negative")
95
- identifier_pattern = (
96
- VALID_IDENTIFIER_REGEX if allow_quoted else UNQUOTED_IDENTIFIER_REGEX
97
- )
98
- pattern = rf"{identifier_pattern}(?:\.{identifier_pattern}){{0,{max_depth}}}"
99
- return re.fullmatch(pattern, name) is not None
100
-
101
-
102
- def to_quoted_identifier(input_value: str) -> str:
103
- """
104
- Turn the input into a valid quoted identifier.
105
- If it is already a valid quoted identifier,
106
- return it as is.
107
- """
108
- if is_valid_quoted_identifier(input_value):
109
- return input_value
110
-
111
- return '"' + input_value.replace('"', '""') + '"'
112
-
113
-
114
- def to_identifier(name: str) -> str:
115
- """
116
- Converts a name to a valid Snowflake identifier. If the name is already a valid
117
- Snowflake identifier, then it is returned unmodified.
118
- """
119
- if is_valid_identifier(name):
120
- return name
121
-
122
- return to_quoted_identifier(name)
123
-
124
-
125
- def identifier_to_str(identifier: str) -> str:
126
- if is_valid_quoted_identifier(identifier):
127
- unquoted_id = identifier[1:-1]
128
- return unquoted_id.replace('""', '"')
129
-
130
- return identifier
131
-
132
-
133
- def append_to_identifier(identifier: str, suffix: str) -> str:
134
- """
135
- Appends a suffix to a valid identifier.
136
- """
137
- if is_valid_unquoted_identifier(identifier):
138
- return to_identifier(f"{identifier}{suffix}")
139
- else:
140
- # the identifier is quoted, so insert the suffix within the quotes
141
- unquoted = identifier[1:-1]
142
- return f'"{unquoted}{suffix}"'
143
-
144
-
145
- def unquote_identifier(identifier: str) -> str:
146
- """
147
- Returns a version of this identifier that can be used inside of a
148
- string for a LIKE clause, or to match an identifier passed back as
149
- a value from a SQL statement.
150
- """
151
- if match := re.fullmatch(QUOTED_IDENTIFIER_REGEX, identifier):
152
- return match.group(1).replace('""', '"')
153
- # unquoted identifiers are internally represented as uppercase
154
- return identifier.upper()
155
-
156
-
157
- def identifier_for_url(identifier: str) -> str:
158
- """
159
- Returns a version of this identifier that can be used as part of a URL.
160
- """
161
- return encode_uri_component(unquote_identifier(identifier))
162
-
163
-
164
- def is_valid_string_literal(literal: str) -> bool:
165
- """
166
- Determines if a literal is a valid single quoted string literal
167
- """
168
- return re.fullmatch(SINGLE_QUOTED_STRING_LITERAL_REGEX, literal) is not None
169
-
170
-
171
- def to_string_literal(raw_value: str) -> str:
172
- """
173
- Converts the raw string value to a correctly escaped, single-quoted string literal.
174
- """
175
- # encode escape sequences
176
- escaped = str(codecs.encode(raw_value, "unicode-escape"), "utf-8")
177
-
178
- # escape single quotes
179
- escaped = re.sub(r"^'|(?<!')'", r"\'", escaped)
180
-
181
- return f"'{escaped}'"
182
-
183
-
184
- def extract_schema(qualified_name: str):
185
- """
186
- Extracts the schema from either a two-part or three-part qualified name
187
- (i.e. schema.object or database.schema.object). If qualified_name is not
188
- qualified with a schema, returns None.
189
- """
190
- if match := re.fullmatch(DB_SCHEMA_AND_NAME, qualified_name):
191
- return match.group(2)
192
- elif match := re.fullmatch(SCHEMA_AND_NAME, qualified_name):
193
- return match.group(1)
194
- return None
195
-
196
-
197
- def first_set_env(*keys: str):
198
- for k in keys:
199
- v = os.getenv(k)
200
- if v:
201
- return v
202
-
203
- return None
204
-
205
-
206
- def get_env_username() -> Optional[str]:
207
- return first_set_env("USER", "USERNAME", "LOGNAME")
208
-
209
-
210
- def concat_identifiers(identifiers: list[str]) -> str:
211
- """
212
- Concatenate multiple identifiers.
213
- If any of them is quoted identifier or contains unsafe characters, quote the result.
214
- Otherwise, the resulting identifier will be unquoted.
215
- """
216
- quotes_found = False
217
- stringified_identifiers: List[str] = []
218
-
219
- for identifier in identifiers:
220
- if is_valid_quoted_identifier(identifier):
221
- quotes_found = True
222
- stringified_identifiers.append(identifier_to_str(identifier))
223
-
224
- concatenated_ids_str = "".join(stringified_identifiers)
225
- if quotes_found:
226
- return to_quoted_identifier(concatenated_ids_str)
227
-
228
- return to_identifier(concatenated_ids_str)
229
-
230
-
231
- SUPPORTED_VERSIONS = [1]
232
-
233
-
234
- def validate_version(version: str):
235
- if version in SUPPORTED_VERSIONS:
236
- raise ValueError(
237
- f"Project definition version {version} is not supported by this version of Snowflake CLI. Supported versions: {SUPPORTED_VERSIONS}"
238
- )
239
-
240
-
241
- def escape_like_pattern(pattern: str, escape_sequence: str = r"\\") -> str:
242
- """
243
- When used with LIKE in Snowflake, '%' and '_' are wildcard characters and must be escaped to be used literally.
244
- The escape character is '\\' when used in SHOW LIKE and must be specified when used with string matching using the
245
- following syntax: <subject> LIKE <pattern> [ ESCAPE <escape> ].
246
- """
247
- pattern = pattern.replace("%", rf"{escape_sequence}%").replace(
248
- "_", rf"{escape_sequence}_"
249
- )
250
- return pattern
251
-
252
-
253
- def identifier_to_show_like_pattern(identifier: str) -> str:
254
- """
255
- Takes an identifier and converts it into a pattern to be used with SHOW ... LIKE ... to get all rows with name
256
- matching this identifier
257
- """
258
- return f"'{escape_like_pattern(unquote_identifier(identifier))}'"
259
-
260
-
261
- def append_test_resource_suffix(identifier: str) -> str:
262
- """
263
- Append a suffix that should be added to specified account-level resources.
264
-
265
- This is an internal concern that is currently only used in tests
266
- to isolate concurrent runs and to add the test name to resources.
267
- """
268
- suffix = os.environ.get(TEST_RESOURCE_SUFFIX_VAR, "")
269
- if identifier_to_str(identifier).endswith(identifier_to_str(suffix)):
270
- # If the suffix has already been added, don't add it again
271
- return identifier
272
- if is_valid_quoted_identifier(identifier) or is_valid_quoted_identifier(suffix):
273
- # If either identifier is already quoted, use concat_identifier
274
- # to add the suffix inside the quotes
275
- return concat_identifiers([identifier, suffix])
276
- # Otherwise just append the string, don't add quotes
277
- # in case the user doesn't want them
278
- return f"{identifier}{suffix}"
@@ -1,13 +0,0 @@
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.
@@ -1,118 +0,0 @@
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
-
16
- from __future__ import annotations
17
-
18
- from pathlib import Path
19
- from textwrap import dedent
20
- from typing import Any, Dict, Optional
21
-
22
- import jinja2
23
- from jinja2 import Environment, StrictUndefined, loaders
24
- from snowflake.cli.api.secure_path import UNLIMITED, SecurePath
25
-
26
- CONTEXT_KEY = "ctx"
27
- FUNCTION_KEY = "fn"
28
-
29
-
30
- def read_file_content(file_name: str):
31
- return SecurePath(file_name).read_text(file_size_limit_mb=UNLIMITED)
32
-
33
-
34
- @jinja2.pass_environment # type: ignore
35
- def procedure_from_js_file(env: jinja2.Environment, file_name: str):
36
- template = env.from_string(
37
- dedent(
38
- """\
39
- var module = {};
40
- var exports = {};
41
- module.exports = exports;
42
- (function() {
43
- {{ code }}
44
- })()
45
- return module.exports.apply(this, arguments);
46
- """
47
- )
48
- )
49
- return template.render(
50
- code=SecurePath(file_name).read_text(file_size_limit_mb=UNLIMITED)
51
- )
52
-
53
-
54
- _CUSTOM_FILTERS = [read_file_content, procedure_from_js_file]
55
-
56
-
57
- def env_bootstrap(env: Environment) -> Environment:
58
- for custom_filter in _CUSTOM_FILTERS:
59
- env.filters[custom_filter.__name__] = custom_filter
60
-
61
- return env
62
-
63
-
64
- class IgnoreAttrEnvironment(Environment):
65
- """
66
- extend Environment class and ignore attributes during rendering.
67
- This ensures that attributes of classes
68
- do not get used during rendering (e.g. __class__, get, etc).
69
- Only dict items can be used for rendering.
70
- """
71
-
72
- def getattr(self, obj, attribute): # noqa: A003
73
- try:
74
- return obj[attribute]
75
- except (TypeError, LookupError, AttributeError):
76
- return self.undefined(obj=obj, name=attribute)
77
-
78
- def getitem(self, obj, argument):
79
- try:
80
- return obj[argument]
81
- except (AttributeError, TypeError, LookupError):
82
- return self.undefined(obj=obj, name=argument)
83
-
84
-
85
- def get_basic_jinja_env(loader: Optional[loaders.BaseLoader] = None) -> Environment:
86
- return env_bootstrap(
87
- IgnoreAttrEnvironment(
88
- loader=loader or loaders.BaseLoader(),
89
- keep_trailing_newline=True,
90
- undefined=StrictUndefined,
91
- )
92
- )
93
-
94
-
95
- def jinja_render_from_file(
96
- template_path: Path, data: Dict[str, Any], output_file_path: Optional[Path] = None
97
- ) -> Optional[str]:
98
- """
99
- Renders a jinja template and outputs either the rendered contents as string or writes to a file.
100
-
101
- Args:
102
- template_path (Path): Path to the template
103
- data (dict): A dictionary of jinja variables and their actual values
104
- output_file_path (Optional[Path]): If provided then rendered template will be written to this file
105
-
106
- Returns:
107
- None if file path is provided, else returns the rendered string.
108
- """
109
- env = get_basic_jinja_env(
110
- loader=loaders.FileSystemLoader(template_path.parent.as_posix())
111
- )
112
- loaded_template = env.get_template(template_path.name)
113
- rendered_result = loaded_template.render(**data)
114
- if output_file_path:
115
- SecurePath(output_file_path).write_text(rendered_result)
116
- return None
117
- else:
118
- return rendered_result
@@ -1,43 +0,0 @@
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 jinja2 import Environment, StrictUndefined, loaders
18
- from snowflake.cli.api.rendering.jinja import (
19
- IgnoreAttrEnvironment,
20
- env_bootstrap,
21
- )
22
-
23
- _YML_TEMPLATE_START = "<%"
24
- _YML_TEMPLATE_END = "%>"
25
-
26
-
27
- def has_client_side_templates(template_content: str) -> bool:
28
- return _YML_TEMPLATE_START in template_content
29
-
30
-
31
- def get_client_side_jinja_env() -> Environment:
32
- _random_block = "___very___unique___block___to___disable___logic___blocks___"
33
- return env_bootstrap(
34
- IgnoreAttrEnvironment(
35
- loader=loaders.BaseLoader(),
36
- keep_trailing_newline=True,
37
- variable_start_string=_YML_TEMPLATE_START,
38
- variable_end_string=_YML_TEMPLATE_END,
39
- block_start_string=_random_block,
40
- block_end_string=_random_block,
41
- undefined=StrictUndefined,
42
- )
43
- )
@@ -1,98 +0,0 @@
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 typing import Any, Dict, List, Optional
18
-
19
- from click import ClickException
20
- from jinja2 import (
21
- Environment,
22
- StrictUndefined,
23
- TemplateSyntaxError,
24
- UndefinedError,
25
- loaders,
26
- )
27
- from snowflake.cli.api.exceptions import InvalidTemplate
28
- from snowflake.cli.api.rendering.jinja import IgnoreAttrEnvironment, env_bootstrap
29
- from snowflake.cli.api.secure_path import SecurePath
30
-
31
- _VARIABLE_TEMPLATE_START = "<!"
32
- _VARIABLE_TEMPLATE_END = "!>"
33
- _BLOCK_TEMPLATE_START = "<!!"
34
- _BLOCK_TEMPLATE_END = "!!>"
35
-
36
-
37
- def to_snowflake_identifier(value: Optional[str]) -> Optional[str]:
38
- if not value:
39
- # passing "None" through filter to allow jinja to handle "undefined value" exception
40
- return value
41
-
42
- import re
43
-
44
- # TODO: remove code duplication when joining "init" with "snow app init"
45
- # See https://docs.snowflake.com/en/sql-reference/identifiers-syntax for identifier syntax
46
- unquoted_identifier_regex = r"([a-zA-Z_])([a-zA-Z0-9_$]{0,254})"
47
- quoted_identifier_regex = r'"((""|[^"]){0,255})"'
48
-
49
- if re.fullmatch(quoted_identifier_regex, value):
50
- return value
51
-
52
- result = re.sub(r"[. -]+", "_", value)
53
- if not re.fullmatch(unquoted_identifier_regex, result):
54
- raise ClickException(
55
- f"Value '{value}' cannot be converted to valid Snowflake identifier."
56
- ' Consider enclosing it in double quotes: ""'
57
- )
58
- return result
59
-
60
-
61
- PROJECT_TEMPLATE_FILTERS = [to_snowflake_identifier]
62
-
63
-
64
- def get_template_cli_jinja_env(template_root: SecurePath) -> Environment:
65
- env = env_bootstrap(
66
- IgnoreAttrEnvironment(
67
- loader=loaders.FileSystemLoader(searchpath=template_root.path),
68
- keep_trailing_newline=True,
69
- variable_start_string=_VARIABLE_TEMPLATE_START,
70
- variable_end_string=_VARIABLE_TEMPLATE_END,
71
- block_start_string=_BLOCK_TEMPLATE_START,
72
- block_end_string=_BLOCK_TEMPLATE_END,
73
- undefined=StrictUndefined,
74
- )
75
- )
76
- env.filters["to_snowflake_identifier"] = to_snowflake_identifier
77
-
78
- return env
79
-
80
-
81
- def render_template_files(
82
- template_root: SecurePath, files_to_render: List[str], data: Dict[str, Any]
83
- ) -> None:
84
- """Override all listed files with their rendered version."""
85
- jinja_env = get_template_cli_jinja_env(template_root)
86
- for path in files_to_render:
87
- try:
88
- jinja_template = jinja_env.get_template(path)
89
- rendered_result = jinja_template.render(**data)
90
- full_path = template_root / path
91
- full_path.write_text(rendered_result)
92
- except TemplateSyntaxError as err:
93
- raise InvalidTemplate(
94
- f"Invalid template syntax in line {err.lineno} of file {path}:\n"
95
- f"{err.message}"
96
- )
97
- except UndefinedError as err:
98
- raise InvalidTemplate(err.message)
@@ -1,105 +0,0 @@
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 typing import Dict, Optional
18
-
19
- from click import ClickException
20
- from jinja2 import Environment, StrictUndefined, loaders, meta
21
- from snowflake.cli.api.cli_global_context import get_cli_context
22
- from snowflake.cli.api.console.console import cli_console
23
- from snowflake.cli.api.exceptions import InvalidTemplate
24
- from snowflake.cli.api.metrics import CLICounterField
25
- from snowflake.cli.api.rendering.jinja import (
26
- CONTEXT_KEY,
27
- FUNCTION_KEY,
28
- IgnoreAttrEnvironment,
29
- env_bootstrap,
30
- )
31
-
32
- _SQL_TEMPLATE_START = "<%"
33
- _SQL_TEMPLATE_END = "%>"
34
- _OLD_SQL_TEMPLATE_START = "&{"
35
- _OLD_SQL_TEMPLATE_END = "}"
36
- RESERVED_KEYS = [CONTEXT_KEY, FUNCTION_KEY]
37
-
38
-
39
- def _get_sql_jinja_env(template_start: str, template_end: str) -> Environment:
40
- _random_block = "___very___unique___block___to___disable___logic___blocks___"
41
- return env_bootstrap(
42
- IgnoreAttrEnvironment(
43
- variable_start_string=template_start,
44
- variable_end_string=template_end,
45
- loader=loaders.BaseLoader(),
46
- block_start_string=_random_block,
47
- block_end_string=_random_block,
48
- keep_trailing_newline=True,
49
- undefined=StrictUndefined,
50
- )
51
- )
52
-
53
-
54
- def _does_template_have_env_syntax(env: Environment, template_content: str) -> bool:
55
- template = env.parse(template_content)
56
- return bool(meta.find_undeclared_variables(template))
57
-
58
-
59
- def has_sql_templates(template_content: str) -> bool:
60
- return (
61
- _OLD_SQL_TEMPLATE_START in template_content
62
- or _SQL_TEMPLATE_START in template_content
63
- )
64
-
65
-
66
- def choose_sql_jinja_env_based_on_template_syntax(
67
- template_content: str, reference_name: Optional[str] = None
68
- ) -> Environment:
69
- old_syntax_env = _get_sql_jinja_env(_OLD_SQL_TEMPLATE_START, _OLD_SQL_TEMPLATE_END)
70
- new_syntax_env = _get_sql_jinja_env(_SQL_TEMPLATE_START, _SQL_TEMPLATE_END)
71
- has_old_syntax = _does_template_have_env_syntax(old_syntax_env, template_content)
72
- has_new_syntax = _does_template_have_env_syntax(new_syntax_env, template_content)
73
- reference_name_str = f" in {reference_name}" if reference_name else ""
74
- if has_old_syntax and has_new_syntax:
75
- raise InvalidTemplate(
76
- f"The SQL query{reference_name_str} mixes {_OLD_SQL_TEMPLATE_START} ... {_OLD_SQL_TEMPLATE_END} syntax"
77
- f" and {_SQL_TEMPLATE_START} ... {_SQL_TEMPLATE_END} syntax."
78
- )
79
- if has_old_syntax:
80
- cli_console.warning(
81
- f"Warning: {_OLD_SQL_TEMPLATE_START} ... {_OLD_SQL_TEMPLATE_END} syntax{reference_name_str} is deprecated."
82
- f" Use {_SQL_TEMPLATE_START} ... {_SQL_TEMPLATE_END} syntax instead."
83
- )
84
- return old_syntax_env
85
- return new_syntax_env
86
-
87
-
88
- def snowflake_sql_jinja_render(content: str, data: Dict | None = None) -> str:
89
- data = data or {}
90
-
91
- for reserved_key in RESERVED_KEYS:
92
- if reserved_key in data:
93
- raise ClickException(
94
- f"{reserved_key} in user defined data. The `{reserved_key}` variable is reserved for CLI usage."
95
- )
96
-
97
- context_data = get_cli_context().template_context
98
- context_data.update(data)
99
- env = choose_sql_jinja_env_based_on_template_syntax(content)
100
-
101
- get_cli_context().metrics.set_counter(
102
- CLICounterField.SQL_TEMPLATES, int(has_sql_templates(content))
103
- )
104
-
105
- return env.from_string(content).render(context_data)