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,28 +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
- import string
16
-
17
-
18
- class _SnowSQLTemplate(string.Template):
19
- delimiter = "&"
20
-
21
-
22
- class _Mapper:
23
- def __getitem__(self, item):
24
- return "&{ " + item + " }"
25
-
26
-
27
- def transpile_snowsql_templates(text: str) -> str:
28
- return _SnowSQLTemplate(text).safe_substitute(_Mapper()) # type: ignore[arg-type]
@@ -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,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 itertools
18
- from os import path
19
- from pathlib import Path
20
- from typing import List, Optional
21
-
22
- import click
23
- import typer
24
- from snowflake.cli.api.cli_global_context import cli_context
25
- from snowflake.cli.api.commands.flags import (
26
- ExecuteVariablesOption,
27
- OnErrorOption,
28
- PatternOption,
29
- like_option,
30
- )
31
- from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
32
- from snowflake.cli.api.console import cli_console
33
- from snowflake.cli.api.constants import ObjectType
34
- from snowflake.cli.api.output.formats import OutputFormat
35
- from snowflake.cli.api.output.types import (
36
- CollectionResult,
37
- CommandResult,
38
- ObjectResult,
39
- QueryResult,
40
- SingleQueryResult,
41
- )
42
- from snowflake.cli.api.utils.path_utils import is_stage_path
43
- from snowflake.cli.plugins.object.command_aliases import (
44
- add_object_command_aliases,
45
- scope_option,
46
- )
47
- from snowflake.cli.plugins.stage.diff import (
48
- DiffResult,
49
- compute_stage_diff,
50
- print_diff_to_console,
51
- )
52
- from snowflake.cli.plugins.stage.manager import OnErrorType, StageManager
53
-
54
- app = SnowTyperFactory(
55
- name="stage",
56
- help="Manages stages.",
57
- )
58
-
59
- StageNameArgument = typer.Argument(..., help="Name of the stage.", show_default=False)
60
-
61
- add_object_command_aliases(
62
- app=app,
63
- object_type=ObjectType.STAGE,
64
- name_argument=StageNameArgument,
65
- like_option=like_option(
66
- help_example='`list --like "my%"` lists all stages that begin with “my”',
67
- ),
68
- scope_option=scope_option(help_example="`list --in database my_db`"),
69
- )
70
-
71
-
72
- @app.command("list-files", requires_connection=True)
73
- def stage_list_files(
74
- stage_name: str = StageNameArgument, pattern=PatternOption, **options
75
- ) -> CommandResult:
76
- """
77
- Lists the stage contents.
78
- """
79
- cursor = StageManager().list_files(stage_name=stage_name, pattern=pattern)
80
- return QueryResult(cursor)
81
-
82
-
83
- @app.command("copy", requires_connection=True)
84
- def copy(
85
- source_path: str = typer.Argument(
86
- help="Source path for copy operation. Can be either stage path or local. You can use a glob pattern for local files but the pattern has to be enclosed in quotes.",
87
- show_default=False,
88
- ),
89
- destination_path: str = typer.Argument(
90
- help="Target directory path for copy operation. Should be stage if source is local or local if source is stage.",
91
- show_default=False,
92
- ),
93
- overwrite: bool = typer.Option(
94
- False,
95
- help="Overwrites existing files in the target path.",
96
- ),
97
- parallel: int = typer.Option(
98
- 4,
99
- help="Number of parallel threads to use when uploading files.",
100
- ),
101
- recursive: bool = typer.Option(
102
- False,
103
- help="Copy files recursively with directory structure.",
104
- ),
105
- auto_compress: bool = typer.Option(
106
- default=False,
107
- help="Specifies whether Snowflake uses gzip to compress files during upload. Ignored when downloading.",
108
- ),
109
- **options,
110
- ) -> CommandResult:
111
- """
112
- Copies all files from target path to target directory. This works for both uploading
113
- to and downloading files from the stage.
114
- """
115
- is_get = is_stage_path(source_path)
116
- is_put = is_stage_path(destination_path)
117
-
118
- if is_get and is_put:
119
- raise click.ClickException(
120
- "Both source and target path are remote. This operation is not supported."
121
- )
122
- if not is_get and not is_put:
123
- raise click.ClickException(
124
- "Both source and target path are local. This operation is not supported."
125
- )
126
-
127
- if is_get:
128
- return get(
129
- recursive=recursive,
130
- source_path=source_path,
131
- destination_path=destination_path,
132
- parallel=parallel,
133
- )
134
- return _put(
135
- recursive=recursive,
136
- source_path=source_path,
137
- destination_path=destination_path,
138
- parallel=parallel,
139
- overwrite=overwrite,
140
- auto_compress=auto_compress,
141
- )
142
-
143
-
144
- @app.command("create", requires_connection=True)
145
- def stage_create(stage_name: str = StageNameArgument, **options) -> CommandResult:
146
- """
147
- Creates a named stage if it does not already exist.
148
- """
149
- cursor = StageManager().create(stage_name=stage_name)
150
- return SingleQueryResult(cursor)
151
-
152
-
153
- @app.command("remove", requires_connection=True)
154
- def stage_remove(
155
- stage_name: str = StageNameArgument,
156
- file_name: str = typer.Argument(
157
- ...,
158
- help="Name of the file to remove.",
159
- show_default=False,
160
- ),
161
- **options,
162
- ) -> CommandResult:
163
- """
164
- Removes a file from a stage.
165
- """
166
-
167
- cursor = StageManager().remove(stage_name=stage_name, path=file_name)
168
- return SingleQueryResult(cursor)
169
-
170
-
171
- @app.command("diff", hidden=True, requires_connection=True)
172
- def stage_diff(
173
- stage_name: str = typer.Argument(
174
- help="Fully qualified name of a stage",
175
- show_default=False,
176
- ),
177
- folder_name: str = typer.Argument(
178
- help="Path to local folder",
179
- show_default=False,
180
- ),
181
- **options,
182
- ) -> Optional[CommandResult]:
183
- """
184
- Diffs a stage with a local folder.
185
- """
186
- diff: DiffResult = compute_stage_diff(
187
- local_root=Path(folder_name), stage_fqn=stage_name
188
- )
189
- if cli_context.output_format == OutputFormat.JSON:
190
- return ObjectResult(diff.to_dict())
191
- else:
192
- print_diff_to_console(diff)
193
- return None # don't print any output
194
-
195
-
196
- @app.command("execute", requires_connection=True)
197
- def execute(
198
- stage_path: str = typer.Argument(
199
- ...,
200
- help="Stage path with files to be execute. For example `@stage/dev/*`.",
201
- show_default=False,
202
- ),
203
- on_error: OnErrorType = OnErrorOption,
204
- variables: Optional[List[str]] = ExecuteVariablesOption,
205
- **options,
206
- ):
207
- """
208
- Execute immediate all files from the stage path. Files can be filtered with glob like pattern,
209
- e.g. `@stage/*.sql`, `@stage/dev/*`. Only files with `.sql` extension will be executed.
210
- """
211
- results = StageManager().execute(
212
- stage_path=stage_path, on_error=on_error, variables=variables
213
- )
214
- return CollectionResult(results)
215
-
216
-
217
- def get(recursive: bool, source_path: str, destination_path: str, parallel: int):
218
- target = Path(destination_path).resolve()
219
- if not recursive:
220
- cli_console.warning(
221
- "Use `--recursive` flag, which copy files recursively with directory structure. This will be the default behavior in the future."
222
- )
223
- cursor = StageManager().get(
224
- stage_path=source_path, dest_path=target, parallel=parallel
225
- )
226
- return QueryResult(cursor)
227
-
228
- cursors = StageManager().get_recursive(
229
- stage_path=source_path, dest_path=target, parallel=parallel
230
- )
231
- results = [list(QueryResult(c).result) for c in cursors]
232
- flattened_results = list(itertools.chain.from_iterable(results))
233
- sorted_results = sorted(
234
- flattened_results,
235
- key=lambda e: (path.dirname(e["file"]), path.basename(e["file"])),
236
- )
237
- return CollectionResult(sorted_results)
238
-
239
-
240
- def _put(
241
- recursive: bool,
242
- source_path: str,
243
- destination_path: str,
244
- parallel: int,
245
- overwrite: bool,
246
- auto_compress: bool,
247
- ):
248
- if recursive:
249
- raise click.ClickException("Recursive flag for upload is not supported.")
250
-
251
- source = Path(source_path).resolve()
252
- local_path = str(source) + "/*" if source.is_dir() else str(source)
253
-
254
- cursor = StageManager().put(
255
- local_path=local_path,
256
- stage_path=destination_path,
257
- overwrite=overwrite,
258
- parallel=parallel,
259
- auto_compress=auto_compress,
260
- )
261
- return QueryResult(cursor)
@@ -1,326 +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 logging
18
- from dataclasses import dataclass, field
19
- from pathlib import Path, PurePosixPath
20
- from typing import Collection, Dict, List, Optional, Tuple
21
-
22
- from snowflake.cli.api.console import cli_console as cc
23
- from snowflake.cli.api.exceptions import (
24
- SnowflakeSQLExecutionError,
25
- )
26
- from snowflake.cli.plugins.nativeapp.artifacts import BundleMap
27
- from snowflake.connector.cursor import DictCursor
28
-
29
- from .manager import StageManager
30
- from .md5 import UnknownMD5FormatError, file_matches_md5sum
31
-
32
- log = logging.getLogger(__name__)
33
-
34
- StagePath = PurePosixPath # alias PurePosixPath as StagePath for clarity
35
-
36
-
37
- @dataclass
38
- class DiffResult:
39
- """
40
- Each collection is a list of stage paths ('/'-separated, regardless of the platform), relative to the stage root.
41
- """
42
-
43
- identical: List[StagePath] = field(default_factory=list)
44
- "Files with matching md5sums"
45
-
46
- different: List[StagePath] = field(default_factory=list)
47
- "Files that may be different between the stage and the local directory"
48
-
49
- only_local: List[StagePath] = field(default_factory=list)
50
- "Files that only exist in the local directory"
51
-
52
- only_on_stage: List[StagePath] = field(default_factory=list)
53
- "Files that only exist on the stage"
54
-
55
- def has_changes(self) -> bool:
56
- return (
57
- len(self.different) > 0
58
- or len(self.only_local) > 0
59
- or len(self.only_on_stage) > 0
60
- )
61
-
62
- def to_dict(self) -> dict:
63
- return {
64
- "modified": [str(p) for p in sorted(self.different)],
65
- "added": [str(p) for p in sorted(self.only_local)],
66
- "deleted": [str(p) for p in sorted(self.only_on_stage)],
67
- }
68
-
69
-
70
- def enumerate_files(path: Path) -> List[Path]:
71
- """
72
- Get a list of all files in a directory (recursively).
73
- """
74
- if not path.is_dir():
75
- raise ValueError("Path must point to a directory")
76
-
77
- paths: List[Path] = []
78
- for child in sorted(path.iterdir()):
79
- if child.is_dir():
80
- paths += enumerate_files(child)
81
- else:
82
- paths.append(child)
83
-
84
- return paths
85
-
86
-
87
- def strip_stage_name(path: str) -> StagePath:
88
- """Returns the given stage path without the stage name as the first part."""
89
- return StagePath(*path.split("/")[1:])
90
-
91
-
92
- def build_md5_map(list_stage_cursor: DictCursor) -> Dict[StagePath, Optional[str]]:
93
- """
94
- Returns a mapping of relative stage paths to their md5sums.
95
- """
96
- return {
97
- strip_stage_name(file["name"]): file["md5"]
98
- for file in list_stage_cursor.fetchall()
99
- }
100
-
101
-
102
- def preserve_from_diff(
103
- diff: DiffResult, stage_paths_to_sync: Collection[StagePath]
104
- ) -> DiffResult:
105
- """
106
- Returns a filtered version of the provided diff, keeping only the provided stage paths.
107
- """
108
- paths_to_preserve = set(stage_paths_to_sync)
109
- preserved_diff: DiffResult = DiffResult()
110
- preserved_diff.identical = [i for i in diff.identical if i in paths_to_preserve]
111
- preserved_diff.different = [i for i in diff.different if i in paths_to_preserve]
112
- preserved_diff.only_local = [i for i in diff.only_local if i in paths_to_preserve]
113
- preserved_diff.only_on_stage = [
114
- i for i in diff.only_on_stage if i in paths_to_preserve
115
- ]
116
- return preserved_diff
117
-
118
-
119
- def compute_stage_diff(
120
- local_root: Path,
121
- stage_fqn: str,
122
- ) -> DiffResult:
123
- """
124
- Diffs the files in a stage with a local folder.
125
- """
126
- stage_manager = StageManager()
127
- local_files = enumerate_files(local_root)
128
- remote_md5 = build_md5_map(stage_manager.list_files(stage_fqn))
129
-
130
- result: DiffResult = DiffResult()
131
-
132
- for local_file in local_files:
133
- relpath = local_file.relative_to(local_root)
134
- stage_path = to_stage_path(relpath)
135
- if stage_path not in remote_md5:
136
- # doesn't exist on the stage
137
- result.only_local.append(stage_path)
138
- else:
139
- # N.B. file size on stage is not always accurate, so cannot fail fast
140
- try:
141
- if file_matches_md5sum(local_file, remote_md5[stage_path]):
142
- # We are assuming that we will not get accidental collisions here due to the
143
- # large space of the md5sum (32 * 4 = 128 bits means 1-in-9-trillion chance)
144
- # combined with the fact that the file name + path must also match elsewhere.
145
- result.identical.append(stage_path)
146
- else:
147
- # either the file has changed, or we can't tell if it has
148
- result.different.append(stage_path)
149
- except UnknownMD5FormatError:
150
- log.warning(
151
- "Could not compare md5 for %s, assuming file has changed",
152
- local_file,
153
- exc_info=True,
154
- )
155
- result.different.append(stage_path)
156
-
157
- # mark this file as seen
158
- del remote_md5[stage_path]
159
-
160
- # every entry here is a file we never saw locally
161
- for stage_path in remote_md5.keys():
162
- result.only_on_stage.append(stage_path)
163
-
164
- return result
165
-
166
-
167
- def get_stage_subpath(stage_path: StagePath) -> str:
168
- """
169
- Returns the parent portion of a stage path, as a string, for inclusion in the fully qualified stage path. Note that
170
- '.' treated specially here, and so the return value of this call is not a `StagePath` instance.
171
- """
172
- parent = str(stage_path.parent)
173
- return "" if parent == "." else parent
174
-
175
-
176
- def to_stage_path(filename: Path) -> StagePath:
177
- """
178
- Returns the stage file name, with the path separator suitably transformed if needed.
179
- """
180
- return StagePath(*filename.parts)
181
-
182
-
183
- def to_local_path(stage_path: StagePath) -> Path:
184
- return Path(*stage_path.parts)
185
-
186
-
187
- def delete_only_on_stage_files(
188
- stage_manager: StageManager,
189
- stage_fqn: str,
190
- only_on_stage: List[StagePath],
191
- role: Optional[str] = None,
192
- ):
193
- """
194
- Deletes all files from a Snowflake stage according to the input list of filenames, using a custom role.
195
- """
196
- for _stage_path in only_on_stage:
197
- stage_manager.remove(stage_name=stage_fqn, path=str(_stage_path), role=role)
198
-
199
-
200
- def put_files_on_stage(
201
- stage_manager: StageManager,
202
- stage_fqn: str,
203
- deploy_root_path: Path,
204
- stage_paths: List[StagePath],
205
- role: Optional[str] = None,
206
- overwrite: bool = False,
207
- ):
208
- """
209
- Uploads all files given input list of filenames on your local filesystem, to a Snowflake stage, using a custom role.
210
- """
211
- for _stage_path in stage_paths:
212
- stage_sub_path = get_stage_subpath(_stage_path)
213
- full_stage_path = (
214
- f"{stage_fqn}/{stage_sub_path}" if stage_sub_path else stage_fqn
215
- )
216
- stage_manager.put(
217
- local_path=deploy_root_path / to_local_path(_stage_path),
218
- stage_path=full_stage_path,
219
- role=role,
220
- overwrite=overwrite,
221
- )
222
-
223
-
224
- def sync_local_diff_with_stage(
225
- role: str, deploy_root_path: Path, diff_result: DiffResult, stage_fqn: str
226
- ):
227
- """
228
- Syncs a given local directory's contents with a Snowflake stage, including removing old files, and re-uploading modified and new files.
229
- """
230
- stage_manager = StageManager()
231
- log.info(
232
- "Uploading diff-ed files from your local %s directory to the Snowflake stage.",
233
- deploy_root_path,
234
- )
235
-
236
- try:
237
- delete_only_on_stage_files(
238
- stage_manager, stage_fqn, diff_result.only_on_stage, role
239
- )
240
- put_files_on_stage(
241
- stage_manager,
242
- stage_fqn,
243
- deploy_root_path,
244
- diff_result.different,
245
- role,
246
- overwrite=True,
247
- )
248
- put_files_on_stage(
249
- stage_manager, stage_fqn, deploy_root_path, diff_result.only_local, role
250
- )
251
- except Exception as err:
252
- # Could be ProgrammingError or IntegrityError from SnowflakeCursor
253
- log.error(err)
254
- raise SnowflakeSQLExecutionError()
255
-
256
-
257
- def _to_src_dest_pair(
258
- stage_path: StagePath, bundle_map: Optional[BundleMap]
259
- ) -> Tuple[Optional[str], str]:
260
- if not bundle_map:
261
- return None, str(stage_path)
262
-
263
- dest_path = to_local_path(stage_path)
264
- src = bundle_map.to_project_path(dest_path)
265
- if src:
266
- return str(src), str(stage_path)
267
-
268
- return "?", str(stage_path)
269
-
270
-
271
- def _to_diff_line(status: str, src: Optional[str], dest: str) -> str:
272
- if src is None:
273
- src_prefix = ""
274
- else:
275
- src_prefix = f"{src} -> "
276
-
277
- longest_status = "modified"
278
- padding = " " * (len(longest_status) - len(status))
279
- status_prefix = f"[red]{status}[/red]: {padding}"
280
-
281
- return f"{status_prefix}{src_prefix}{dest}"
282
-
283
-
284
- def print_diff_to_console(
285
- diff: DiffResult,
286
- bundle_map: Optional[BundleMap] = None,
287
- ):
288
- if not diff.has_changes():
289
- cc.message("Your stage is up-to-date with your local deploy root.")
290
- return
291
-
292
- blank_line_needed = False
293
- if diff.only_local or diff.different:
294
- cc.message("Local changes to be deployed:")
295
- messages_to_output = []
296
- for p in diff.different:
297
- src_dest_pair = _to_src_dest_pair(p, bundle_map)
298
- messages_to_output.append(
299
- (
300
- src_dest_pair,
301
- _to_diff_line("modified", src_dest_pair[0], src_dest_pair[1]),
302
- )
303
- )
304
- for p in diff.only_local:
305
- src_dest_pair = _to_src_dest_pair(p, bundle_map)
306
- messages_to_output.append(
307
- (
308
- src_dest_pair,
309
- _to_diff_line("added", src_dest_pair[0], src_dest_pair[1]),
310
- )
311
- )
312
-
313
- with cc.indented():
314
- for key, message in sorted(messages_to_output, key=lambda pair: pair[0]):
315
- cc.message(message)
316
-
317
- blank_line_needed = True
318
-
319
- if diff.only_on_stage:
320
- if blank_line_needed:
321
- cc.message("")
322
- cc.message(f"Deleted paths to be removed from your stage:")
323
- with cc.indented():
324
- for p in sorted(diff.only_on_stage):
325
- diff_line = _to_diff_line("deleted", src=None, dest=str(p))
326
- cc.message(diff_line)