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,878 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import time
4
- from contextlib import contextmanager
5
- from datetime import datetime
6
- from pathlib import Path
7
- from textwrap import dedent
8
- from typing import Callable, Generator, List, Literal, Optional, TypedDict
9
-
10
- import typer
11
- from click import ClickException, UsageError
12
- from pydantic import Field, field_validator
13
- from snowflake.cli._plugins.connection.util import make_snowsight_url
14
- from snowflake.cli._plugins.nativeapp.common_flags import (
15
- ForceOption,
16
- InteractiveOption,
17
- ValidateOption,
18
- )
19
- from snowflake.cli._plugins.nativeapp.constants import (
20
- ALLOWED_SPECIAL_COMMENTS,
21
- COMMENT_COL,
22
- NAME_COL,
23
- OWNER_COL,
24
- SPECIAL_COMMENT,
25
- )
26
- from snowflake.cli._plugins.nativeapp.entities.application_package import (
27
- ApplicationPackageEntity,
28
- ApplicationPackageEntityModel,
29
- )
30
- from snowflake.cli._plugins.nativeapp.exceptions import (
31
- ApplicationPackageDoesNotExistError,
32
- NoEventTableForAccount,
33
- )
34
- from snowflake.cli._plugins.nativeapp.policy import (
35
- AllowAlwaysPolicy,
36
- AskAlwaysPolicy,
37
- DenyAlwaysPolicy,
38
- PolicyBase,
39
- )
40
- from snowflake.cli._plugins.nativeapp.same_account_install_method import (
41
- SameAccountInstallMethod,
42
- )
43
- from snowflake.cli._plugins.nativeapp.utils import needs_confirmation
44
- from snowflake.cli._plugins.workspace.action_context import ActionContext
45
- from snowflake.cli.api.cli_global_context import get_cli_context
46
- from snowflake.cli.api.console.abc import AbstractConsole
47
- from snowflake.cli.api.entities.common import EntityBase, get_sql_executor
48
- from snowflake.cli.api.entities.utils import (
49
- drop_generic_object,
50
- execute_post_deploy_hooks,
51
- generic_sql_error_handler,
52
- print_messages,
53
- )
54
- from snowflake.cli.api.errno import (
55
- APPLICATION_NO_LONGER_AVAILABLE,
56
- CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION,
57
- CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES,
58
- NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
59
- ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
60
- )
61
- from snowflake.cli.api.metrics import CLICounterField
62
- from snowflake.cli.api.project.schemas.entities.common import (
63
- EntityModelBase,
64
- Identifier,
65
- PostDeployHook,
66
- TargetField,
67
- )
68
- from snowflake.cli.api.project.schemas.updatable_model import DiscriminatorField
69
- from snowflake.cli.api.project.util import (
70
- append_test_resource_suffix,
71
- extract_schema,
72
- identifier_for_url,
73
- unquote_identifier,
74
- )
75
- from snowflake.connector import DictCursor, ProgrammingError
76
-
77
- # Reasons why an `alter application ... upgrade` might fail
78
- UPGRADE_RESTRICTION_CODES = {
79
- CANNOT_UPGRADE_FROM_LOOSE_FILES_TO_VERSION,
80
- CANNOT_UPGRADE_FROM_VERSION_TO_LOOSE_FILES,
81
- ONLY_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
82
- NOT_SUPPORTED_ON_DEV_MODE_APPLICATIONS,
83
- APPLICATION_NO_LONGER_AVAILABLE,
84
- }
85
-
86
- ApplicationOwnedObject = TypedDict("ApplicationOwnedObject", {"name": str, "type": str})
87
-
88
-
89
- class ApplicationEntityModel(EntityModelBase):
90
- type: Literal["application"] = DiscriminatorField() # noqa A003
91
- from_: TargetField[ApplicationPackageEntityModel] = Field(
92
- alias="from",
93
- title="An application package this entity should be created from",
94
- )
95
- debug: Optional[bool] = Field(
96
- title="Whether to enable debug mode when using a named stage to create an application object",
97
- default=None,
98
- )
99
-
100
- @field_validator("identifier")
101
- @classmethod
102
- def append_test_resource_suffix_to_identifier(
103
- cls, input_value: Identifier | str
104
- ) -> Identifier | str:
105
- identifier = (
106
- input_value.name if isinstance(input_value, Identifier) else input_value
107
- )
108
- with_suffix = append_test_resource_suffix(identifier)
109
- if isinstance(input_value, Identifier):
110
- return input_value.model_copy(update=dict(name=with_suffix))
111
- return with_suffix
112
-
113
-
114
- class ApplicationEntity(EntityBase[ApplicationEntityModel]):
115
- """
116
- A Native App application object, created from an application package.
117
- """
118
-
119
- def action_deploy(
120
- self,
121
- ctx: ActionContext,
122
- from_release_directive: bool,
123
- prune: bool,
124
- recursive: bool,
125
- paths: List[Path],
126
- validate: bool = ValidateOption,
127
- stage_fqn: Optional[str] = None,
128
- interactive: bool = InteractiveOption,
129
- version: Optional[str] = None,
130
- patch: Optional[int] = None,
131
- force: Optional[bool] = ForceOption,
132
- *args,
133
- **kwargs,
134
- ):
135
- model = self._entity_model
136
- app_name = model.fqn.identifier
137
- debug_mode = model.debug
138
- if model.meta:
139
- app_role = model.meta.role or ctx.default_role
140
- app_warehouse = model.meta.warehouse or ctx.default_warehouse
141
- post_deploy_hooks = model.meta.post_deploy
142
- else:
143
- app_role = ctx.default_role
144
- app_warehouse = ctx.default_warehouse
145
- post_deploy_hooks = None
146
-
147
- package_entity: ApplicationPackageEntity = ctx.get_entity(model.from_.target)
148
- package_model: ApplicationPackageEntityModel = (
149
- package_entity._entity_model # noqa: SLF001
150
- )
151
- package_name = package_model.fqn.identifier
152
- if package_model.meta and package_model.meta.role:
153
- package_role = package_model.meta.role
154
- else:
155
- package_role = ctx.default_role
156
-
157
- if not stage_fqn:
158
- stage_fqn = f"{package_name}.{package_model.stage}"
159
- stage_schema = extract_schema(stage_fqn)
160
-
161
- is_interactive = False
162
- if force:
163
- policy = AllowAlwaysPolicy()
164
- elif interactive:
165
- is_interactive = True
166
- policy = AskAlwaysPolicy()
167
- else:
168
- policy = DenyAlwaysPolicy()
169
-
170
- def deploy_package():
171
- package_entity.action_deploy(
172
- ctx=ctx,
173
- prune=True,
174
- recursive=True,
175
- paths=[],
176
- validate=validate,
177
- stage_fqn=stage_fqn,
178
- interactive=interactive,
179
- force=force,
180
- )
181
-
182
- self.deploy(
183
- console=ctx.console,
184
- project_root=ctx.project_root,
185
- app_name=app_name,
186
- app_role=app_role,
187
- app_warehouse=app_warehouse,
188
- package_name=package_name,
189
- package_role=package_role,
190
- stage_schema=stage_schema,
191
- stage_fqn=stage_fqn,
192
- debug_mode=debug_mode,
193
- validate=validate,
194
- from_release_directive=from_release_directive,
195
- is_interactive=is_interactive,
196
- policy=policy,
197
- version=version,
198
- patch=patch,
199
- post_deploy_hooks=post_deploy_hooks,
200
- deploy_package=deploy_package,
201
- )
202
-
203
- def action_drop(
204
- self,
205
- ctx: ActionContext,
206
- interactive: bool,
207
- force_drop: bool = False,
208
- cascade: Optional[bool] = None,
209
- *args,
210
- **kwargs,
211
- ):
212
- model = self._entity_model
213
- app_name = model.fqn.identifier
214
- if model.meta and model.meta.role:
215
- app_role = model.meta.role
216
- else:
217
- app_role = ctx.default_role
218
- self.drop(
219
- console=ctx.console,
220
- app_name=app_name,
221
- app_role=app_role,
222
- auto_yes=force_drop,
223
- interactive=interactive,
224
- cascade=cascade,
225
- )
226
-
227
- @classmethod
228
- def drop(
229
- cls,
230
- console: AbstractConsole,
231
- app_name: str,
232
- app_role: str,
233
- auto_yes: bool,
234
- interactive: bool = False,
235
- cascade: Optional[bool] = None,
236
- ):
237
- """
238
- Attempts to drop the application object if all validations and user prompts allow so.
239
- """
240
-
241
- needs_confirm = True
242
-
243
- # 1. If existing application is not found, exit gracefully
244
- show_obj_row = cls.get_existing_app_info(
245
- app_name=app_name,
246
- app_role=app_role,
247
- )
248
- if show_obj_row is None:
249
- console.warning(
250
- f"Role {app_role} does not own any application object with the name {app_name}, or the application object does not exist."
251
- )
252
- return
253
-
254
- # 2. Check if created by the Snowflake CLI
255
- row_comment = show_obj_row[COMMENT_COL]
256
- if row_comment not in ALLOWED_SPECIAL_COMMENTS and needs_confirmation(
257
- needs_confirm, auto_yes
258
- ):
259
- should_drop_object = typer.confirm(
260
- dedent(
261
- f"""\
262
- Application object {app_name} was not created by Snowflake CLI.
263
- Application object details:
264
- Name: {app_name}
265
- Created on: {show_obj_row["created_on"]}
266
- Source: {show_obj_row["source"]}
267
- Owner: {show_obj_row[OWNER_COL]}
268
- Comment: {show_obj_row[COMMENT_COL]}
269
- Version: {show_obj_row["version"]}
270
- Patch: {show_obj_row["patch"]}
271
- Are you sure you want to drop it?
272
- """
273
- )
274
- )
275
- if not should_drop_object:
276
- console.message(f"Did not drop application object {app_name}.")
277
- # The user desires to keep the app, therefore we can't proceed since it would
278
- # leave behind an orphan app when we get to dropping the package
279
- raise typer.Abort()
280
-
281
- # 3. Check for application objects owned by the application
282
- # This query will fail if the application package has already been dropped, so handle this case gracefully
283
- has_objects_to_drop = False
284
- message_prefix = ""
285
- cascade_true_message = ""
286
- cascade_false_message = ""
287
- interactive_prompt = ""
288
- non_interactive_abort = ""
289
- try:
290
- if application_objects := cls.get_objects_owned_by_application(
291
- app_name=app_name,
292
- app_role=app_role,
293
- ):
294
- has_objects_to_drop = True
295
- message_prefix = (
296
- f"The following objects are owned by application {app_name}"
297
- )
298
- cascade_true_message = f"{message_prefix} and will be dropped:"
299
- cascade_false_message = f"{message_prefix} and will NOT be dropped:"
300
- interactive_prompt = "Would you like to drop these objects in addition to the application? [y/n/ABORT]"
301
- non_interactive_abort = "Re-run teardown again with --cascade or --no-cascade to specify whether these objects should be dropped along with the application"
302
- except ProgrammingError as e:
303
- if e.errno != APPLICATION_NO_LONGER_AVAILABLE:
304
- raise
305
- application_objects = []
306
- message_prefix = (
307
- f"Could not determine which objects are owned by application {app_name}"
308
- )
309
- has_objects_to_drop = True # potentially, but we don't know what they are
310
- cascade_true_message = (
311
- f"{message_prefix}, an unknown number of objects will be dropped."
312
- )
313
- cascade_false_message = f"{message_prefix}, they will NOT be dropped."
314
- interactive_prompt = f"Would you like to drop an unknown set of objects in addition to the application? [y/n/ABORT]"
315
- non_interactive_abort = f"Re-run teardown again with --cascade or --no-cascade to specify whether any objects should be dropped along with the application."
316
-
317
- if has_objects_to_drop:
318
- if cascade is True:
319
- # If the user explicitly passed the --cascade flag
320
- console.message(cascade_true_message)
321
- with console.indented():
322
- for obj in application_objects:
323
- console.message(cls.application_object_to_str(obj))
324
- elif cascade is False:
325
- # If the user explicitly passed the --no-cascade flag
326
- console.message(cascade_false_message)
327
- with console.indented():
328
- for obj in application_objects:
329
- console.message(cls.application_object_to_str(obj))
330
- elif interactive:
331
- # If the user didn't pass any cascade flag and the session is interactive
332
- console.message(message_prefix)
333
- with console.indented():
334
- for obj in application_objects:
335
- console.message(cls.application_object_to_str(obj))
336
- user_response = typer.prompt(
337
- interactive_prompt,
338
- show_default=False,
339
- default="ABORT",
340
- ).lower()
341
- if user_response in ["y", "yes"]:
342
- cascade = True
343
- elif user_response in ["n", "no"]:
344
- cascade = False
345
- else:
346
- raise typer.Abort()
347
- else:
348
- # Else abort since we don't know what to do and can't ask the user
349
- console.message(message_prefix)
350
- with console.indented():
351
- for obj in application_objects:
352
- console.message(cls.application_object_to_str(obj))
353
- console.message(non_interactive_abort)
354
- raise typer.Abort()
355
- elif cascade is None:
356
- # If there's nothing to drop, set cascade to an explicit False value
357
- cascade = False
358
-
359
- # 4. All validations have passed, drop object
360
- drop_generic_object(
361
- console=console,
362
- object_type="application",
363
- object_name=app_name,
364
- role=app_role,
365
- cascade=cascade,
366
- )
367
- return # The application object was successfully dropped, therefore exit gracefully
368
-
369
- @staticmethod
370
- def get_objects_owned_by_application(
371
- app_name: str,
372
- app_role: str,
373
- ) -> List[ApplicationOwnedObject]:
374
- """
375
- Returns all application objects owned by this application.
376
- """
377
- sql_executor = get_sql_executor()
378
- with sql_executor.use_role(app_role):
379
- results = sql_executor.execute_query(
380
- f"show objects owned by application {app_name}"
381
- ).fetchall()
382
- return [{"name": row[1], "type": row[2]} for row in results]
383
-
384
- @classmethod
385
- def application_objects_to_str(
386
- cls, application_objects: list[ApplicationOwnedObject]
387
- ) -> str:
388
- """
389
- Returns a list in an "(Object Type) Object Name" format. Database-level and schema-level object names are fully qualified:
390
- (COMPUTE_POOL) POOL_NAME
391
- (DATABASE) DB_NAME
392
- (SCHEMA) DB_NAME.PUBLIC
393
- ...
394
- """
395
- return "\n".join(
396
- [cls.application_object_to_str(obj) for obj in application_objects]
397
- )
398
-
399
- @staticmethod
400
- def application_object_to_str(obj: ApplicationOwnedObject) -> str:
401
- return f"({obj['type']}) {obj['name']}"
402
-
403
- @classmethod
404
- def deploy(
405
- cls,
406
- console: AbstractConsole,
407
- project_root: Path,
408
- app_name: str,
409
- app_role: str,
410
- app_warehouse: str,
411
- package_name: str,
412
- package_role: str,
413
- stage_schema: str,
414
- stage_fqn: str,
415
- debug_mode: bool,
416
- validate: bool,
417
- from_release_directive: bool,
418
- is_interactive: bool,
419
- policy: PolicyBase,
420
- deploy_package: Callable,
421
- version: Optional[str] = None,
422
- patch: Optional[int] = None,
423
- post_deploy_hooks: Optional[List[PostDeployHook]] = None,
424
- drop_application_before_upgrade: Optional[Callable] = None,
425
- ):
426
- """
427
- Create or upgrade the application object using the given strategy
428
- (unversioned dev, versioned dev, or same-account release directive).
429
- """
430
-
431
- # same-account release directive
432
- if from_release_directive:
433
- cls.create_or_upgrade_app(
434
- console=console,
435
- project_root=project_root,
436
- package_name=package_name,
437
- package_role=package_role,
438
- app_name=app_name,
439
- app_role=app_role,
440
- app_warehouse=app_warehouse,
441
- stage_schema=stage_schema,
442
- stage_fqn=stage_fqn,
443
- debug_mode=debug_mode,
444
- policy=policy,
445
- install_method=SameAccountInstallMethod.release_directive(),
446
- is_interactive=is_interactive,
447
- post_deploy_hooks=post_deploy_hooks,
448
- drop_application_before_upgrade=drop_application_before_upgrade,
449
- )
450
- return
451
-
452
- # versioned dev
453
- if version:
454
- try:
455
- version_exists = ApplicationPackageEntity.get_existing_version_info(
456
- version=version,
457
- package_name=package_name,
458
- package_role=package_role,
459
- )
460
- if not version_exists:
461
- raise UsageError(
462
- f"Application package {package_name} does not have any version {version} defined. Use 'snow app version create' to define a version in the application package first."
463
- )
464
- except ApplicationPackageDoesNotExistError as app_err:
465
- raise UsageError(
466
- f"Application package {package_name} does not exist. Use 'snow app version create' to first create an application package and then define a version in it."
467
- )
468
-
469
- cls.create_or_upgrade_app(
470
- console=console,
471
- project_root=project_root,
472
- package_name=package_name,
473
- package_role=package_role,
474
- app_name=app_name,
475
- app_role=app_role,
476
- app_warehouse=app_warehouse,
477
- stage_schema=stage_schema,
478
- stage_fqn=stage_fqn,
479
- debug_mode=debug_mode,
480
- policy=policy,
481
- install_method=SameAccountInstallMethod.versioned_dev(version, patch),
482
- is_interactive=is_interactive,
483
- post_deploy_hooks=post_deploy_hooks,
484
- drop_application_before_upgrade=drop_application_before_upgrade,
485
- )
486
- return
487
-
488
- # unversioned dev
489
- deploy_package()
490
- cls.create_or_upgrade_app(
491
- console=console,
492
- project_root=project_root,
493
- package_name=package_name,
494
- package_role=package_role,
495
- app_name=app_name,
496
- app_role=app_role,
497
- app_warehouse=app_warehouse,
498
- stage_schema=stage_schema,
499
- stage_fqn=stage_fqn,
500
- debug_mode=debug_mode,
501
- policy=policy,
502
- install_method=SameAccountInstallMethod.unversioned_dev(),
503
- is_interactive=is_interactive,
504
- post_deploy_hooks=post_deploy_hooks,
505
- drop_application_before_upgrade=drop_application_before_upgrade,
506
- )
507
-
508
- @classmethod
509
- def create_or_upgrade_app(
510
- cls,
511
- console: AbstractConsole,
512
- project_root: Path,
513
- package_name: str,
514
- package_role: str,
515
- app_name: str,
516
- app_role: str,
517
- app_warehouse: Optional[str],
518
- stage_schema: Optional[str],
519
- stage_fqn: str,
520
- debug_mode: bool,
521
- policy: PolicyBase,
522
- install_method: SameAccountInstallMethod,
523
- is_interactive: bool = False,
524
- post_deploy_hooks: Optional[List[PostDeployHook]] = None,
525
- drop_application_before_upgrade: Optional[Callable] = None,
526
- ):
527
- sql_executor = get_sql_executor()
528
- with sql_executor.use_role(app_role):
529
-
530
- # 1. Need to use a warehouse to create an application object
531
- with sql_executor.use_warehouse(app_warehouse):
532
-
533
- # 2. Check for an existing application by the same name
534
- show_app_row = cls.get_existing_app_info(
535
- app_name=app_name,
536
- app_role=app_role,
537
- )
538
-
539
- # 3. If existing application is found, perform a few validations and upgrade the application object.
540
- if show_app_row:
541
-
542
- install_method.ensure_app_usable(
543
- app_name=app_name,
544
- app_role=app_role,
545
- show_app_row=show_app_row,
546
- )
547
-
548
- # If all the above checks are in order, proceed to upgrade
549
- try:
550
- console.step(
551
- f"Upgrading existing application object {app_name}."
552
- )
553
- using_clause = install_method.using_clause(stage_fqn)
554
- upgrade_cursor = sql_executor.execute_query(
555
- f"alter application {app_name} upgrade {using_clause}",
556
- )
557
- print_messages(console, upgrade_cursor)
558
-
559
- if install_method.is_dev_mode:
560
- # if debug_mode is present (controlled), ensure it is up-to-date
561
- if debug_mode is not None:
562
- sql_executor.execute_query(
563
- f"alter application {app_name} set debug_mode = {debug_mode}"
564
- )
565
-
566
- # hooks always executed after a create or upgrade
567
- cls.execute_post_deploy_hooks(
568
- console=console,
569
- project_root=project_root,
570
- post_deploy_hooks=post_deploy_hooks,
571
- app_name=app_name,
572
- app_warehouse=app_warehouse,
573
- )
574
- return
575
-
576
- except ProgrammingError as err:
577
- if err.errno not in UPGRADE_RESTRICTION_CODES:
578
- generic_sql_error_handler(err=err)
579
- else: # The existing application object was created from a different process.
580
- console.warning(err.msg)
581
- # TODO Drop the entity here instead of taking a callback once action_drop() is implemented
582
- if drop_application_before_upgrade:
583
- drop_application_before_upgrade()
584
- else:
585
- raise NotImplementedError
586
-
587
- # 4. With no (more) existing application objects, create an application object using the release directives
588
- console.step(f"Creating new application object {app_name} in account.")
589
-
590
- if app_role != package_role:
591
- with sql_executor.use_role(package_role):
592
- sql_executor.execute_query(
593
- f"grant install, develop on application package {package_name} to role {app_role}"
594
- )
595
- sql_executor.execute_query(
596
- f"grant usage on schema {package_name}.{stage_schema} to role {app_role}"
597
- )
598
- sql_executor.execute_query(
599
- f"grant read on stage {stage_fqn} to role {app_role}"
600
- )
601
-
602
- try:
603
- # by default, applications are created in debug mode when possible;
604
- # this can be overridden in the project definition
605
- debug_mode_clause = ""
606
- if install_method.is_dev_mode:
607
- initial_debug_mode = (
608
- debug_mode if debug_mode is not None else True
609
- )
610
- debug_mode_clause = f"debug_mode = {initial_debug_mode}"
611
-
612
- using_clause = install_method.using_clause(stage_fqn)
613
- create_cursor = sql_executor.execute_query(
614
- dedent(
615
- f"""\
616
- create application {app_name}
617
- from application package {package_name} {using_clause} {debug_mode_clause}
618
- comment = {SPECIAL_COMMENT}
619
- """
620
- ),
621
- )
622
- print_messages(console, create_cursor)
623
-
624
- # hooks always executed after a create or upgrade
625
- cls.execute_post_deploy_hooks(
626
- console=console,
627
- project_root=project_root,
628
- post_deploy_hooks=post_deploy_hooks,
629
- app_name=app_name,
630
- app_warehouse=app_warehouse,
631
- )
632
-
633
- except ProgrammingError as err:
634
- generic_sql_error_handler(err)
635
-
636
- @classmethod
637
- def execute_post_deploy_hooks(
638
- cls,
639
- console: AbstractConsole,
640
- project_root: Path,
641
- post_deploy_hooks: Optional[List[PostDeployHook]],
642
- app_name: str,
643
- app_warehouse: Optional[str],
644
- ):
645
- get_cli_context().metrics.set_counter_default(
646
- CLICounterField.POST_DEPLOY_SCRIPTS, 0
647
- )
648
-
649
- if post_deploy_hooks:
650
- with cls.use_application_warehouse(app_warehouse):
651
- execute_post_deploy_hooks(
652
- console=console,
653
- project_root=project_root,
654
- post_deploy_hooks=post_deploy_hooks,
655
- deployed_object_type="application",
656
- database_name=app_name,
657
- )
658
-
659
- @staticmethod
660
- @contextmanager
661
- def use_application_warehouse(
662
- app_warehouse: Optional[str],
663
- ):
664
- if app_warehouse:
665
- with get_sql_executor().use_warehouse(app_warehouse):
666
- yield
667
- else:
668
- raise ClickException(
669
- dedent(
670
- f"""\
671
- Application warehouse cannot be empty.
672
- Please provide a value for it in your connection information or your project definition file.
673
- """
674
- )
675
- )
676
-
677
- @staticmethod
678
- def get_existing_app_info(
679
- app_name: str,
680
- app_role: str,
681
- ) -> Optional[dict]:
682
- """
683
- Check for an existing application object by the same name as in project definition, in account.
684
- It executes a 'show applications like' query and returns the result as single row, if one exists.
685
- """
686
- sql_executor = get_sql_executor()
687
- with sql_executor.use_role(app_role):
688
- return sql_executor.show_specific_object(
689
- "applications", app_name, name_col=NAME_COL
690
- )
691
-
692
- @classmethod
693
- def get_events(
694
- cls,
695
- app_name: str,
696
- package_name: str,
697
- since: str | datetime | None = None,
698
- until: str | datetime | None = None,
699
- record_types: list[str] | None = None,
700
- scopes: list[str] | None = None,
701
- consumer_org: str = "",
702
- consumer_account: str = "",
703
- consumer_app_hash: str = "",
704
- first: int = -1,
705
- last: int = -1,
706
- ):
707
-
708
- record_types = record_types or []
709
- scopes = scopes or []
710
-
711
- if first >= 0 and last >= 0:
712
- raise ValueError("first and last cannot be used together")
713
-
714
- account_event_table = cls.get_account_event_table()
715
- if not account_event_table:
716
- raise NoEventTableForAccount()
717
-
718
- # resource_attributes uses the unquoted/uppercase app and package name
719
- app_name = unquote_identifier(app_name)
720
- package_name = unquote_identifier(package_name)
721
- org_name = unquote_identifier(consumer_org)
722
- account_name = unquote_identifier(consumer_account)
723
-
724
- # Filter on record attributes
725
- if consumer_org and consumer_account:
726
- # Look for events shared from a consumer account
727
- app_clause = (
728
- f"resource_attributes:\"snow.application.package.name\" = '{package_name}' "
729
- f"and resource_attributes:\"snow.application.consumer.organization\" = '{org_name}' "
730
- f"and resource_attributes:\"snow.application.consumer.name\" = '{account_name}'"
731
- )
732
- if consumer_app_hash:
733
- # If the user has specified a hash of a specific app installation
734
- # in the consumer account, filter events to that installation only
735
- app_clause += f" and resource_attributes:\"snow.database.hash\" = '{consumer_app_hash.lower()}'"
736
- else:
737
- # Otherwise look for events from an app installed in the same account as the package
738
- app_clause = f"resource_attributes:\"snow.database.name\" = '{app_name}'"
739
-
740
- # Filter on event time
741
- if isinstance(since, datetime):
742
- since_clause = f"and timestamp >= '{since}'"
743
- elif isinstance(since, str) and since:
744
- since_clause = f"and timestamp >= sysdate() - interval '{since}'"
745
- else:
746
- since_clause = ""
747
- if isinstance(until, datetime):
748
- until_clause = f"and timestamp <= '{until}'"
749
- elif isinstance(until, str) and until:
750
- until_clause = f"and timestamp <= sysdate() - interval '{until}'"
751
- else:
752
- until_clause = ""
753
-
754
- # Filter on event type (log, span, span_event)
755
- type_in_values = ",".join(f"'{v}'" for v in record_types)
756
- types_clause = (
757
- f"and record_type in ({type_in_values})" if type_in_values else ""
758
- )
759
-
760
- # Filter on event scope (e.g. the logger name)
761
- scope_in_values = ",".join(f"'{v}'" for v in scopes)
762
- scopes_clause = (
763
- f"and scope:name in ({scope_in_values})" if scope_in_values else ""
764
- )
765
-
766
- # Limit event count
767
- first_clause = f"limit {first}" if first >= 0 else ""
768
- last_clause = f"limit {last}" if last >= 0 else ""
769
-
770
- query = dedent(
771
- f"""\
772
- select * from (
773
- select timestamp, value::varchar value
774
- from {account_event_table}
775
- where ({app_clause})
776
- {since_clause}
777
- {until_clause}
778
- {types_clause}
779
- {scopes_clause}
780
- order by timestamp desc
781
- {last_clause}
782
- ) order by timestamp asc
783
- {first_clause}
784
- """
785
- )
786
- sql_executor = get_sql_executor()
787
- try:
788
- return sql_executor.execute_query(query, cursor_class=DictCursor).fetchall()
789
- except ProgrammingError as err:
790
- generic_sql_error_handler(err)
791
-
792
- @classmethod
793
- def stream_events(
794
- cls,
795
- app_name: str,
796
- package_name: str,
797
- interval_seconds: int,
798
- since: str | datetime | None = None,
799
- record_types: list[str] | None = None,
800
- scopes: list[str] | None = None,
801
- consumer_org: str = "",
802
- consumer_account: str = "",
803
- consumer_app_hash: str = "",
804
- last: int = -1,
805
- ) -> Generator[dict, None, None]:
806
- try:
807
- events = cls.get_events(
808
- app_name=app_name,
809
- package_name=package_name,
810
- since=since,
811
- record_types=record_types,
812
- scopes=scopes,
813
- consumer_org=consumer_org,
814
- consumer_account=consumer_account,
815
- consumer_app_hash=consumer_app_hash,
816
- last=last,
817
- )
818
- yield from events # Yield the initial batch of events
819
- last_event_time = events[-1]["TIMESTAMP"] if events else None
820
-
821
- while True: # Then infinite poll for new events
822
- time.sleep(interval_seconds)
823
- previous_events = events
824
- events = cls.get_events(
825
- app_name=app_name,
826
- package_name=package_name,
827
- since=last_event_time,
828
- record_types=record_types,
829
- scopes=scopes,
830
- consumer_org=consumer_org,
831
- consumer_account=consumer_account,
832
- consumer_app_hash=consumer_app_hash,
833
- )
834
- if not events:
835
- continue
836
-
837
- yield from _new_events_only(previous_events, events)
838
- last_event_time = events[-1]["TIMESTAMP"]
839
- except KeyboardInterrupt:
840
- return
841
-
842
- @staticmethod
843
- def get_account_event_table():
844
- query = "show parameters like 'event_table' in account"
845
- sql_executor = get_sql_executor()
846
- results = sql_executor.execute_query(query, cursor_class=DictCursor)
847
- return next((r["value"] for r in results if r["key"] == "EVENT_TABLE"), "")
848
-
849
- @classmethod
850
- def get_snowsight_url(cls, app_name: str, app_warehouse: str | None) -> str:
851
- """Returns the URL that can be used to visit this app via Snowsight."""
852
- name = identifier_for_url(app_name)
853
- with cls.use_application_warehouse(app_warehouse):
854
- sql_executor = get_sql_executor()
855
- return make_snowsight_url(
856
- sql_executor._conn, f"/#/apps/application/{name}" # noqa: SLF001
857
- )
858
-
859
-
860
- def _new_events_only(previous_events: list[dict], new_events: list[dict]) -> list[dict]:
861
- # The timestamp that overlaps between both sets of events
862
- overlap_time = new_events[0]["TIMESTAMP"]
863
-
864
- # Remove all the events from the new result set
865
- # if they were already printed. We iterate and remove
866
- # instead of filtering in order to handle duplicates
867
- # (i.e. if an event is present 3 times in new_events
868
- # but only once in previous_events, it should still
869
- # appear twice in new_events at the end
870
- new_events = new_events.copy()
871
- for event in reversed(previous_events):
872
- if event["TIMESTAMP"] < overlap_time:
873
- break
874
- # No need to handle ValueError here since we know
875
- # that events that pass the above if check will
876
- # either be in both lists or in new_events only
877
- new_events.remove(event)
878
- return new_events