snowflake-cli-labs 2.8.0rc1__py3-none-any.whl → 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 (242) hide show
  1. README.md +21 -0
  2. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-2.8.2.dist-info}/METADATA +7 -95
  3. snowflake_cli_labs-2.8.2.dist-info/RECORD +5 -0
  4. snowflake/cli/__about__.py +0 -17
  5. snowflake/cli/__init__.py +0 -13
  6. snowflake/cli/api/__init__.py +0 -48
  7. snowflake/cli/api/cli_global_context.py +0 -390
  8. snowflake/cli/api/commands/__init__.py +0 -13
  9. snowflake/cli/api/commands/alias.py +0 -23
  10. snowflake/cli/api/commands/decorators.py +0 -354
  11. snowflake/cli/api/commands/execution_metadata.py +0 -40
  12. snowflake/cli/api/commands/experimental_behaviour.py +0 -19
  13. snowflake/cli/api/commands/flags.py +0 -640
  14. snowflake/cli/api/commands/project_initialisation.py +0 -65
  15. snowflake/cli/api/commands/snow_typer.py +0 -237
  16. snowflake/cli/api/commands/typer_pre_execute.py +0 -26
  17. snowflake/cli/api/config.py +0 -348
  18. snowflake/cli/api/console/__init__.py +0 -17
  19. snowflake/cli/api/console/abc.py +0 -89
  20. snowflake/cli/api/console/console.py +0 -134
  21. snowflake/cli/api/console/enum.py +0 -17
  22. snowflake/cli/api/constants.py +0 -79
  23. snowflake/cli/api/errno.py +0 -27
  24. snowflake/cli/api/exceptions.py +0 -164
  25. snowflake/cli/api/feature_flags.py +0 -55
  26. snowflake/cli/api/identifiers.py +0 -154
  27. snowflake/cli/api/output/__init__.py +0 -13
  28. snowflake/cli/api/output/formats.py +0 -20
  29. snowflake/cli/api/output/types.py +0 -118
  30. snowflake/cli/api/plugins/__init__.py +0 -13
  31. snowflake/cli/api/plugins/command/__init__.py +0 -72
  32. snowflake/cli/api/plugins/command/plugin_hook_specs.py +0 -21
  33. snowflake/cli/api/plugins/plugin_config.py +0 -32
  34. snowflake/cli/api/project/__init__.py +0 -13
  35. snowflake/cli/api/project/definition.py +0 -84
  36. snowflake/cli/api/project/definition_manager.py +0 -134
  37. snowflake/cli/api/project/errors.py +0 -56
  38. snowflake/cli/api/project/project_verification.py +0 -23
  39. snowflake/cli/api/project/schemas/__init__.py +0 -13
  40. snowflake/cli/api/project/schemas/entities/application_entity.py +0 -44
  41. snowflake/cli/api/project/schemas/entities/application_package_entity.py +0 -66
  42. snowflake/cli/api/project/schemas/entities/common.py +0 -78
  43. snowflake/cli/api/project/schemas/entities/entities.py +0 -30
  44. snowflake/cli/api/project/schemas/identifier_model.py +0 -49
  45. snowflake/cli/api/project/schemas/native_app/__init__.py +0 -13
  46. snowflake/cli/api/project/schemas/native_app/application.py +0 -62
  47. snowflake/cli/api/project/schemas/native_app/native_app.py +0 -93
  48. snowflake/cli/api/project/schemas/native_app/package.py +0 -78
  49. snowflake/cli/api/project/schemas/native_app/path_mapping.py +0 -65
  50. snowflake/cli/api/project/schemas/project_definition.py +0 -199
  51. snowflake/cli/api/project/schemas/snowpark/__init__.py +0 -13
  52. snowflake/cli/api/project/schemas/snowpark/argument.py +0 -28
  53. snowflake/cli/api/project/schemas/snowpark/callable.py +0 -69
  54. snowflake/cli/api/project/schemas/snowpark/snowpark.py +0 -36
  55. snowflake/cli/api/project/schemas/streamlit/__init__.py +0 -13
  56. snowflake/cli/api/project/schemas/streamlit/streamlit.py +0 -46
  57. snowflake/cli/api/project/schemas/template.py +0 -77
  58. snowflake/cli/api/project/schemas/updatable_model.py +0 -194
  59. snowflake/cli/api/project/util.py +0 -261
  60. snowflake/cli/api/rendering/__init__.py +0 -13
  61. snowflake/cli/api/rendering/jinja.py +0 -112
  62. snowflake/cli/api/rendering/project_definition_templates.py +0 -39
  63. snowflake/cli/api/rendering/project_templates.py +0 -98
  64. snowflake/cli/api/rendering/sql_templates.py +0 -60
  65. snowflake/cli/api/rest_api.py +0 -172
  66. snowflake/cli/api/sanitizers.py +0 -43
  67. snowflake/cli/api/secure_path.py +0 -362
  68. snowflake/cli/api/secure_utils.py +0 -29
  69. snowflake/cli/api/sql_execution.py +0 -260
  70. snowflake/cli/api/utils/__init__.py +0 -13
  71. snowflake/cli/api/utils/cursor.py +0 -34
  72. snowflake/cli/api/utils/definition_rendering.py +0 -383
  73. snowflake/cli/api/utils/dict_utils.py +0 -73
  74. snowflake/cli/api/utils/error_handling.py +0 -23
  75. snowflake/cli/api/utils/graph.py +0 -97
  76. snowflake/cli/api/utils/models.py +0 -63
  77. snowflake/cli/api/utils/naming_utils.py +0 -13
  78. snowflake/cli/api/utils/path_utils.py +0 -36
  79. snowflake/cli/api/utils/templating_functions.py +0 -144
  80. snowflake/cli/api/utils/types.py +0 -35
  81. snowflake/cli/app/__init__.py +0 -22
  82. snowflake/cli/app/__main__.py +0 -31
  83. snowflake/cli/app/api_impl/__init__.py +0 -13
  84. snowflake/cli/app/api_impl/plugin/__init__.py +0 -13
  85. snowflake/cli/app/api_impl/plugin/plugin_config_provider_impl.py +0 -66
  86. snowflake/cli/app/build_and_push.sh +0 -8
  87. snowflake/cli/app/cli_app.py +0 -243
  88. snowflake/cli/app/commands_registration/__init__.py +0 -33
  89. snowflake/cli/app/commands_registration/builtin_plugins.py +0 -54
  90. snowflake/cli/app/commands_registration/command_plugins_loader.py +0 -169
  91. snowflake/cli/app/commands_registration/commands_registration_with_callbacks.py +0 -105
  92. snowflake/cli/app/commands_registration/exception_logging.py +0 -26
  93. snowflake/cli/app/commands_registration/threadsafe.py +0 -48
  94. snowflake/cli/app/commands_registration/typer_registration.py +0 -153
  95. snowflake/cli/app/constants.py +0 -19
  96. snowflake/cli/app/dev/__init__.py +0 -13
  97. snowflake/cli/app/dev/commands_structure.py +0 -48
  98. snowflake/cli/app/dev/docs/__init__.py +0 -13
  99. snowflake/cli/app/dev/docs/commands_docs_generator.py +0 -100
  100. snowflake/cli/app/dev/docs/generator.py +0 -35
  101. snowflake/cli/app/dev/docs/project_definition_docs_generator.py +0 -58
  102. snowflake/cli/app/dev/docs/project_definition_generate_json_schema.py +0 -227
  103. snowflake/cli/app/dev/docs/template_utils.py +0 -23
  104. snowflake/cli/app/dev/docs/templates/definition_description.rst.jinja2 +0 -38
  105. snowflake/cli/app/dev/docs/templates/overview.rst.jinja2 +0 -9
  106. snowflake/cli/app/dev/docs/templates/usage.rst.jinja2 +0 -57
  107. snowflake/cli/app/dev/pycharm_remote_debug.py +0 -46
  108. snowflake/cli/app/loggers.py +0 -199
  109. snowflake/cli/app/main_typer.py +0 -62
  110. snowflake/cli/app/printing.py +0 -181
  111. snowflake/cli/app/snow_connector.py +0 -243
  112. snowflake/cli/app/telemetry.py +0 -189
  113. snowflake/cli/plugins/__init__.py +0 -13
  114. snowflake/cli/plugins/connection/__init__.py +0 -13
  115. snowflake/cli/plugins/connection/commands.py +0 -330
  116. snowflake/cli/plugins/connection/plugin_spec.py +0 -30
  117. snowflake/cli/plugins/connection/util.py +0 -179
  118. snowflake/cli/plugins/cortex/__init__.py +0 -13
  119. snowflake/cli/plugins/cortex/commands.py +0 -327
  120. snowflake/cli/plugins/cortex/constants.py +0 -17
  121. snowflake/cli/plugins/cortex/manager.py +0 -189
  122. snowflake/cli/plugins/cortex/plugin_spec.py +0 -30
  123. snowflake/cli/plugins/cortex/types.py +0 -22
  124. snowflake/cli/plugins/git/__init__.py +0 -13
  125. snowflake/cli/plugins/git/commands.py +0 -305
  126. snowflake/cli/plugins/git/manager.py +0 -96
  127. snowflake/cli/plugins/git/plugin_spec.py +0 -30
  128. snowflake/cli/plugins/init/__init__.py +0 -13
  129. snowflake/cli/plugins/init/commands.py +0 -244
  130. snowflake/cli/plugins/init/plugin_spec.py +0 -30
  131. snowflake/cli/plugins/nativeapp/__init__.py +0 -13
  132. snowflake/cli/plugins/nativeapp/artifacts.py +0 -742
  133. snowflake/cli/plugins/nativeapp/codegen/__init__.py +0 -13
  134. snowflake/cli/plugins/nativeapp/codegen/artifact_processor.py +0 -91
  135. snowflake/cli/plugins/nativeapp/codegen/compiler.py +0 -130
  136. snowflake/cli/plugins/nativeapp/codegen/sandbox.py +0 -306
  137. snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +0 -172
  138. snowflake/cli/plugins/nativeapp/codegen/setup/setup_driver.py.source +0 -56
  139. snowflake/cli/plugins/nativeapp/codegen/snowpark/callback_source.py.jinja +0 -181
  140. snowflake/cli/plugins/nativeapp/codegen/snowpark/extension_function_utils.py +0 -217
  141. snowflake/cli/plugins/nativeapp/codegen/snowpark/models.py +0 -61
  142. snowflake/cli/plugins/nativeapp/codegen/snowpark/python_processor.py +0 -528
  143. snowflake/cli/plugins/nativeapp/commands.py +0 -439
  144. snowflake/cli/plugins/nativeapp/common_flags.py +0 -44
  145. snowflake/cli/plugins/nativeapp/constants.py +0 -27
  146. snowflake/cli/plugins/nativeapp/exceptions.py +0 -122
  147. snowflake/cli/plugins/nativeapp/feature_flags.py +0 -24
  148. snowflake/cli/plugins/nativeapp/init.py +0 -345
  149. snowflake/cli/plugins/nativeapp/manager.py +0 -823
  150. snowflake/cli/plugins/nativeapp/plugin_spec.py +0 -30
  151. snowflake/cli/plugins/nativeapp/policy.py +0 -50
  152. snowflake/cli/plugins/nativeapp/project_model.py +0 -195
  153. snowflake/cli/plugins/nativeapp/run_processor.py +0 -389
  154. snowflake/cli/plugins/nativeapp/teardown_processor.py +0 -301
  155. snowflake/cli/plugins/nativeapp/utils.py +0 -98
  156. snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +0 -135
  157. snowflake/cli/plugins/nativeapp/version/__init__.py +0 -13
  158. snowflake/cli/plugins/nativeapp/version/commands.py +0 -170
  159. snowflake/cli/plugins/nativeapp/version/version_processor.py +0 -362
  160. snowflake/cli/plugins/notebook/__init__.py +0 -13
  161. snowflake/cli/plugins/notebook/commands.py +0 -84
  162. snowflake/cli/plugins/notebook/exceptions.py +0 -20
  163. snowflake/cli/plugins/notebook/manager.py +0 -71
  164. snowflake/cli/plugins/notebook/plugin_spec.py +0 -30
  165. snowflake/cli/plugins/notebook/types.py +0 -16
  166. snowflake/cli/plugins/object/__init__.py +0 -13
  167. snowflake/cli/plugins/object/command_aliases.py +0 -94
  168. snowflake/cli/plugins/object/commands.py +0 -174
  169. snowflake/cli/plugins/object/common.py +0 -85
  170. snowflake/cli/plugins/object/manager.py +0 -96
  171. snowflake/cli/plugins/object/plugin_spec.py +0 -30
  172. snowflake/cli/plugins/object_stage_deprecated/__init__.py +0 -15
  173. snowflake/cli/plugins/object_stage_deprecated/commands.py +0 -122
  174. snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py +0 -32
  175. snowflake/cli/plugins/snowpark/__init__.py +0 -13
  176. snowflake/cli/plugins/snowpark/commands.py +0 -548
  177. snowflake/cli/plugins/snowpark/common.py +0 -307
  178. snowflake/cli/plugins/snowpark/manager.py +0 -109
  179. snowflake/cli/plugins/snowpark/models.py +0 -156
  180. snowflake/cli/plugins/snowpark/package/__init__.py +0 -13
  181. snowflake/cli/plugins/snowpark/package/anaconda_packages.py +0 -233
  182. snowflake/cli/plugins/snowpark/package/commands.py +0 -256
  183. snowflake/cli/plugins/snowpark/package/manager.py +0 -43
  184. snowflake/cli/plugins/snowpark/package/utils.py +0 -26
  185. snowflake/cli/plugins/snowpark/package_utils.py +0 -354
  186. snowflake/cli/plugins/snowpark/plugin_spec.py +0 -30
  187. snowflake/cli/plugins/snowpark/snowpark_package_paths.py +0 -65
  188. snowflake/cli/plugins/snowpark/snowpark_shared.py +0 -95
  189. snowflake/cli/plugins/snowpark/zipper.py +0 -81
  190. snowflake/cli/plugins/spcs/__init__.py +0 -35
  191. snowflake/cli/plugins/spcs/common.py +0 -99
  192. snowflake/cli/plugins/spcs/compute_pool/__init__.py +0 -13
  193. snowflake/cli/plugins/spcs/compute_pool/commands.py +0 -240
  194. snowflake/cli/plugins/spcs/compute_pool/manager.py +0 -121
  195. snowflake/cli/plugins/spcs/image_registry/__init__.py +0 -13
  196. snowflake/cli/plugins/spcs/image_registry/commands.py +0 -65
  197. snowflake/cli/plugins/spcs/image_registry/manager.py +0 -105
  198. snowflake/cli/plugins/spcs/image_repository/__init__.py +0 -13
  199. snowflake/cli/plugins/spcs/image_repository/commands.py +0 -196
  200. snowflake/cli/plugins/spcs/image_repository/manager.py +0 -84
  201. snowflake/cli/plugins/spcs/jobs/__init__.py +0 -13
  202. snowflake/cli/plugins/spcs/jobs/commands.py +0 -78
  203. snowflake/cli/plugins/spcs/jobs/manager.py +0 -53
  204. snowflake/cli/plugins/spcs/plugin_spec.py +0 -30
  205. snowflake/cli/plugins/spcs/services/__init__.py +0 -13
  206. snowflake/cli/plugins/spcs/services/commands.py +0 -311
  207. snowflake/cli/plugins/spcs/services/manager.py +0 -170
  208. snowflake/cli/plugins/sql/__init__.py +0 -13
  209. snowflake/cli/plugins/sql/commands.py +0 -83
  210. snowflake/cli/plugins/sql/manager.py +0 -92
  211. snowflake/cli/plugins/sql/plugin_spec.py +0 -30
  212. snowflake/cli/plugins/sql/snowsql_templating.py +0 -28
  213. snowflake/cli/plugins/stage/__init__.py +0 -13
  214. snowflake/cli/plugins/stage/commands.py +0 -261
  215. snowflake/cli/plugins/stage/diff.py +0 -326
  216. snowflake/cli/plugins/stage/manager.py +0 -544
  217. snowflake/cli/plugins/stage/md5.py +0 -160
  218. snowflake/cli/plugins/stage/plugin_spec.py +0 -30
  219. snowflake/cli/plugins/streamlit/__init__.py +0 -13
  220. snowflake/cli/plugins/streamlit/commands.py +0 -186
  221. snowflake/cli/plugins/streamlit/manager.py +0 -222
  222. snowflake/cli/plugins/streamlit/plugin_spec.py +0 -30
  223. snowflake/cli/plugins/workspace/__init__.py +0 -13
  224. snowflake/cli/plugins/workspace/commands.py +0 -35
  225. snowflake/cli/plugins/workspace/plugin_spec.py +0 -30
  226. snowflake/cli/templates/default_snowpark/.gitignore +0 -4
  227. snowflake/cli/templates/default_snowpark/app/__init__.py +0 -0
  228. snowflake/cli/templates/default_snowpark/app/common.py +0 -2
  229. snowflake/cli/templates/default_snowpark/app/functions.py +0 -15
  230. snowflake/cli/templates/default_snowpark/app/procedures.py +0 -22
  231. snowflake/cli/templates/default_snowpark/requirements.txt +0 -1
  232. snowflake/cli/templates/default_snowpark/snowflake.yml +0 -23
  233. snowflake/cli/templates/default_streamlit/.gitignore +0 -4
  234. snowflake/cli/templates/default_streamlit/common/hello.py +0 -2
  235. snowflake/cli/templates/default_streamlit/environment.yml +0 -6
  236. snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -3
  237. snowflake/cli/templates/default_streamlit/snowflake.yml +0 -10
  238. snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -4
  239. snowflake_cli_labs-2.8.0rc1.dist-info/RECORD +0 -240
  240. snowflake_cli_labs-2.8.0rc1.dist-info/entry_points.txt +0 -2
  241. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-2.8.2.dist-info}/WHEEL +0 -0
  242. {snowflake_cli_labs-2.8.0rc1.dist-info → snowflake_cli_labs-2.8.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,261 +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
-
38
- def encode_uri_component(s: str) -> str:
39
- """
40
- Implementation of JavaScript's encodeURIComponent.
41
- """
42
- return quote(s, safe="!~*'()")
43
-
44
-
45
- def sanitize_identifier(input_: str):
46
- """
47
- Removes characters that cannot be used in an unquoted identifier.
48
- If the identifier does not start with a letter or underscore, prefix it with an underscore.
49
- Limits the identifier to 255 characters.
50
- """
51
- value = re.sub(r"[^a-zA-Z0-9_$]", "", f"{input_}")
52
-
53
- # if it does not start with a letter or underscore, prefix it with an underscore
54
- if not value or not re.match(r"[a-zA-Z_]", value[0]):
55
- value = f"_{value}"
56
-
57
- # limit it to 255 characters
58
- return value[:255]
59
-
60
-
61
- def is_valid_unquoted_identifier(identifier: str) -> bool:
62
- """
63
- Determines whether the provided identifier is a valid Snowflake unquoted identifier.
64
- """
65
- return re.fullmatch(UNQUOTED_IDENTIFIER_REGEX, identifier) is not None
66
-
67
-
68
- def is_valid_quoted_identifier(identifier: str) -> bool:
69
- """
70
- Determines whether the provided identifier is a valid Snowflake quoted identifier.
71
- """
72
- return re.fullmatch(QUOTED_IDENTIFIER_REGEX, identifier) is not None
73
-
74
-
75
- def is_valid_identifier(identifier: str) -> bool:
76
- """
77
- Determines whether the provided identifier is a valid Snowflake quoted or unquoted identifier.
78
- """
79
- return is_valid_unquoted_identifier(identifier) or is_valid_quoted_identifier(
80
- identifier
81
- )
82
-
83
-
84
- def is_valid_object_name(name: str, max_depth=2, allow_quoted=True) -> bool:
85
- """
86
- Determines whether the given identifier is a valid object name in the form <name>, <schema>.<name>, or <database>.<schema>.<name>.
87
- Max_depth determines how many valid identifiers are allowed. For example, account level objects would have a max depth of 0
88
- because they cannot be qualified by a database or schema, just the single identifier.
89
- """
90
- if max_depth < 0:
91
- raise ValueError("max_depth must be non-negative")
92
- identifier_pattern = (
93
- VALID_IDENTIFIER_REGEX if allow_quoted else UNQUOTED_IDENTIFIER_REGEX
94
- )
95
- pattern = rf"{identifier_pattern}(?:\.{identifier_pattern}){{0,{max_depth}}}"
96
- return re.fullmatch(pattern, name) is not None
97
-
98
-
99
- def to_quoted_identifier(input_value: str) -> str:
100
- """
101
- Turn the input into a valid quoted identifier.
102
- If it is already a valid quoted identifier,
103
- return it as is.
104
- """
105
- if is_valid_quoted_identifier(input_value):
106
- return input_value
107
-
108
- return '"' + input_value.replace('"', '""') + '"'
109
-
110
-
111
- def to_identifier(name: str) -> str:
112
- """
113
- Converts a name to a valid Snowflake identifier. If the name is already a valid
114
- Snowflake identifier, then it is returned unmodified.
115
- """
116
- if is_valid_identifier(name):
117
- return name
118
-
119
- return to_quoted_identifier(name)
120
-
121
-
122
- def identifier_to_str(identifier: str) -> str:
123
- if is_valid_quoted_identifier(identifier):
124
- unquoted_id = identifier[1:-1]
125
- return unquoted_id.replace('""', '"')
126
-
127
- return identifier
128
-
129
-
130
- def append_to_identifier(identifier: str, suffix: str) -> str:
131
- """
132
- Appends a suffix to a valid identifier.
133
- """
134
- if is_valid_unquoted_identifier(identifier):
135
- return to_identifier(f"{identifier}{suffix}")
136
- else:
137
- # the identifier is quoted, so insert the suffix within the quotes
138
- unquoted = identifier[1:-1]
139
- return f'"{unquoted}{suffix}"'
140
-
141
-
142
- def unquote_identifier(identifier: str) -> str:
143
- """
144
- Returns a version of this identifier that can be used inside of a
145
- string for a LIKE clause, or to match an identifier passed back as
146
- a value from a SQL statement.
147
- """
148
- if match := re.fullmatch(QUOTED_IDENTIFIER_REGEX, identifier):
149
- return match.group(1).replace('""', '"')
150
- # unquoted identifiers are internally represented as uppercase
151
- return identifier.upper()
152
-
153
-
154
- def identifier_for_url(identifier: str) -> str:
155
- """
156
- Returns a version of this identifier that can be used as part of a URL.
157
- """
158
- return encode_uri_component(unquote_identifier(identifier))
159
-
160
-
161
- def is_valid_string_literal(literal: str) -> bool:
162
- """
163
- Determines if a literal is a valid single quoted string literal
164
- """
165
- return re.fullmatch(SINGLE_QUOTED_STRING_LITERAL_REGEX, literal) is not None
166
-
167
-
168
- def to_string_literal(raw_value: str) -> str:
169
- """
170
- Converts the raw string value to a correctly escaped, single-quoted string literal.
171
- """
172
- # encode escape sequences
173
- escaped = str(codecs.encode(raw_value, "unicode-escape"), "utf-8")
174
-
175
- # escape single quotes
176
- escaped = re.sub(r"^'|(?<!')'", r"\'", escaped)
177
-
178
- return f"'{escaped}'"
179
-
180
-
181
- def extract_schema(qualified_name: str):
182
- """
183
- Extracts the schema from either a two-part or three-part qualified name
184
- (i.e. schema.object or database.schema.object). If qualified_name is not
185
- qualified with a schema, returns None.
186
- """
187
- if match := re.fullmatch(DB_SCHEMA_AND_NAME, qualified_name):
188
- return match.group(2)
189
- elif match := re.fullmatch(SCHEMA_AND_NAME, qualified_name):
190
- return match.group(1)
191
- return None
192
-
193
-
194
- def generate_user_env(username: str) -> dict:
195
- return {
196
- "USER": username,
197
- }
198
-
199
-
200
- def first_set_env(*keys: str):
201
- for k in keys:
202
- v = os.getenv(k)
203
- if v:
204
- return v
205
-
206
- return None
207
-
208
-
209
- def get_env_username() -> Optional[str]:
210
- return first_set_env("USER", "USERNAME", "LOGNAME")
211
-
212
-
213
- def concat_identifiers(identifiers: list[str]) -> str:
214
- """
215
- Concatenate multiple identifiers.
216
- If any of them is quoted identifier or contains unsafe characters, quote the result.
217
- Otherwise, the resulting identifier will be unquoted.
218
- """
219
- quotes_found = False
220
- stringified_identifiers: List[str] = []
221
-
222
- for identifier in identifiers:
223
- if is_valid_quoted_identifier(identifier):
224
- quotes_found = True
225
- stringified_identifiers.append(identifier_to_str(identifier))
226
-
227
- concatenated_ids_str = "".join(stringified_identifiers)
228
- if quotes_found:
229
- return to_quoted_identifier(concatenated_ids_str)
230
-
231
- return to_identifier(concatenated_ids_str)
232
-
233
-
234
- SUPPORTED_VERSIONS = [1]
235
-
236
-
237
- def validate_version(version: str):
238
- if version in SUPPORTED_VERSIONS:
239
- raise ValueError(
240
- f"Project definition version {version} is not supported by this version of Snowflake CLI. Supported versions: {SUPPORTED_VERSIONS}"
241
- )
242
-
243
-
244
- def escape_like_pattern(pattern: str, escape_sequence: str = r"\\") -> str:
245
- """
246
- When used with LIKE in Snowflake, '%' and '_' are wildcard characters and must be escaped to be used literally.
247
- The escape character is '\\' when used in SHOW LIKE and must be specified when used with string matching using the
248
- following syntax: <subject> LIKE <pattern> [ ESCAPE <escape> ].
249
- """
250
- pattern = pattern.replace("%", rf"{escape_sequence}%").replace(
251
- "_", rf"{escape_sequence}_"
252
- )
253
- return pattern
254
-
255
-
256
- def identifier_to_show_like_pattern(identifier: str) -> str:
257
- """
258
- Takes an identifier and converts it into a pattern to be used with SHOW ... LIKE ... to get all rows with name
259
- matching this identifier
260
- """
261
- return f"'{escape_like_pattern(unquote_identifier(identifier))}'"
@@ -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,112 +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 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 jinja_render_from_file(
86
- template_path: Path, data: Dict, output_file_path: Optional[Path] = None
87
- ) -> Optional[str]:
88
- """
89
- Renders a jinja template and outputs either the rendered contents as string or writes to a file.
90
-
91
- Args:
92
- template_path (Path): Path to the template
93
- data (dict): A dictionary of jinja variables and their actual values
94
- output_file_path (Optional[Path]): If provided then rendered template will be written to this file
95
-
96
- Returns:
97
- None if file path is provided, else returns the rendered string.
98
- """
99
- env = env_bootstrap(
100
- IgnoreAttrEnvironment(
101
- loader=loaders.FileSystemLoader(template_path.parent),
102
- keep_trailing_newline=True,
103
- undefined=StrictUndefined,
104
- )
105
- )
106
- loaded_template = env.get_template(template_path.name)
107
- rendered_result = loaded_template.render(**data)
108
- if output_file_path:
109
- SecurePath(output_file_path).write_text(rendered_result)
110
- return None
111
- else:
112
- return rendered_result
@@ -1,39 +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 get_project_definition_cli_jinja_env() -> Environment:
28
- _random_block = "___very___unique___block___to___disable___logic___blocks___"
29
- return env_bootstrap(
30
- IgnoreAttrEnvironment(
31
- loader=loaders.BaseLoader(),
32
- keep_trailing_newline=True,
33
- variable_start_string=_YML_TEMPLATE_START,
34
- variable_end_string=_YML_TEMPLATE_END,
35
- block_start_string=_random_block,
36
- block_end_string=_random_block,
37
- undefined=StrictUndefined,
38
- )
39
- )
@@ -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,60 +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 StrictUndefined, loaders
21
- from snowflake.cli.api.cli_global_context import cli_context
22
- from snowflake.cli.api.rendering.jinja import (
23
- CONTEXT_KEY,
24
- FUNCTION_KEY,
25
- IgnoreAttrEnvironment,
26
- env_bootstrap,
27
- )
28
-
29
- _SQL_TEMPLATE_START = "&{"
30
- _SQL_TEMPLATE_END = "}"
31
- RESERVED_KEYS = [CONTEXT_KEY, FUNCTION_KEY]
32
-
33
-
34
- def get_sql_cli_jinja_env(*, loader: Optional[loaders.BaseLoader] = None):
35
- _random_block = "___very___unique___block___to___disable___logic___blocks___"
36
- return env_bootstrap(
37
- IgnoreAttrEnvironment(
38
- loader=loader or loaders.BaseLoader(),
39
- keep_trailing_newline=True,
40
- variable_start_string=_SQL_TEMPLATE_START,
41
- variable_end_string=_SQL_TEMPLATE_END,
42
- block_start_string=_random_block,
43
- block_end_string=_random_block,
44
- undefined=StrictUndefined,
45
- )
46
- )
47
-
48
-
49
- def snowflake_sql_jinja_render(content: str, data: Dict | None = None) -> str:
50
- data = data or {}
51
-
52
- for reserved_key in RESERVED_KEYS:
53
- if reserved_key in data:
54
- raise ClickException(
55
- f"{reserved_key} in user defined data. The `{reserved_key}` variable is reserved for CLI usage."
56
- )
57
-
58
- context_data = cli_context.template_context
59
- context_data.update(data)
60
- return get_sql_cli_jinja_env().from_string(content).render(**context_data)