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