snowflake-cli-labs 2.6.1__py3-none-any.whl → 2.7.0rc1__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 (84) hide show
  1. snowflake/cli/__about__.py +1 -1
  2. snowflake/cli/api/cli_global_context.py +9 -0
  3. snowflake/cli/api/commands/decorators.py +9 -4
  4. snowflake/cli/api/commands/execution_metadata.py +40 -0
  5. snowflake/cli/api/commands/flags.py +45 -36
  6. snowflake/cli/api/commands/project_initialisation.py +5 -2
  7. snowflake/cli/api/commands/snow_typer.py +20 -9
  8. snowflake/cli/api/errno.py +27 -0
  9. snowflake/cli/api/feature_flags.py +1 -0
  10. snowflake/cli/api/identifiers.py +20 -3
  11. snowflake/cli/api/output/types.py +9 -0
  12. snowflake/cli/api/project/definition_manager.py +2 -2
  13. snowflake/cli/api/project/project_verification.py +23 -0
  14. snowflake/cli/api/project/schemas/entities/application_entity.py +50 -0
  15. snowflake/cli/api/project/schemas/entities/application_package_entity.py +63 -0
  16. snowflake/cli/api/project/schemas/entities/common.py +85 -0
  17. snowflake/cli/api/project/schemas/entities/entities.py +30 -0
  18. snowflake/cli/api/project/schemas/project_definition.py +114 -22
  19. snowflake/cli/api/project/schemas/streamlit/streamlit.py +5 -4
  20. snowflake/cli/api/project/schemas/template.py +77 -0
  21. snowflake/cli/{plugins/nativeapp/errno.py → api/rendering/__init__.py} +0 -2
  22. snowflake/cli/api/{utils/rendering.py → rendering/jinja.py} +3 -48
  23. snowflake/cli/api/rendering/project_definition_templates.py +39 -0
  24. snowflake/cli/api/rendering/project_templates.py +97 -0
  25. snowflake/cli/api/rendering/sql_templates.py +56 -0
  26. snowflake/cli/api/sql_execution.py +40 -1
  27. snowflake/cli/api/utils/definition_rendering.py +8 -5
  28. snowflake/cli/app/commands_registration/builtin_plugins.py +4 -0
  29. snowflake/cli/app/dev/docs/project_definition_docs_generator.py +2 -2
  30. snowflake/cli/app/loggers.py +3 -1
  31. snowflake/cli/app/printing.py +17 -7
  32. snowflake/cli/app/snow_connector.py +9 -1
  33. snowflake/cli/app/telemetry.py +41 -2
  34. snowflake/cli/plugins/connection/commands.py +4 -3
  35. snowflake/cli/plugins/connection/util.py +73 -18
  36. snowflake/cli/plugins/cortex/commands.py +2 -1
  37. snowflake/cli/plugins/git/commands.py +20 -4
  38. snowflake/cli/plugins/git/manager.py +44 -20
  39. snowflake/cli/plugins/init/__init__.py +13 -0
  40. snowflake/cli/plugins/init/commands.py +242 -0
  41. snowflake/cli/plugins/init/plugin_spec.py +30 -0
  42. snowflake/cli/plugins/nativeapp/codegen/artifact_processor.py +40 -0
  43. snowflake/cli/plugins/nativeapp/codegen/compiler.py +57 -27
  44. snowflake/cli/plugins/nativeapp/codegen/sandbox.py +99 -10
  45. snowflake/cli/plugins/nativeapp/codegen/setup/native_app_setup_processor.py +172 -0
  46. snowflake/cli/plugins/nativeapp/codegen/setup/setup_driver.py.source +56 -0
  47. snowflake/cli/plugins/nativeapp/codegen/snowpark/python_processor.py +21 -21
  48. snowflake/cli/plugins/nativeapp/commands.py +69 -6
  49. snowflake/cli/plugins/nativeapp/constants.py +0 -6
  50. snowflake/cli/plugins/nativeapp/exceptions.py +37 -12
  51. snowflake/cli/plugins/nativeapp/init.py +1 -1
  52. snowflake/cli/plugins/nativeapp/manager.py +114 -39
  53. snowflake/cli/plugins/nativeapp/project_model.py +8 -4
  54. snowflake/cli/plugins/nativeapp/run_processor.py +117 -102
  55. snowflake/cli/plugins/nativeapp/teardown_processor.py +7 -2
  56. snowflake/cli/plugins/nativeapp/v2_conversions/v2_to_v1_decorator.py +146 -0
  57. snowflake/cli/plugins/nativeapp/version/commands.py +19 -3
  58. snowflake/cli/plugins/nativeapp/version/version_processor.py +11 -3
  59. snowflake/cli/plugins/snowpark/commands.py +34 -26
  60. snowflake/cli/plugins/snowpark/common.py +88 -27
  61. snowflake/cli/plugins/snowpark/manager.py +16 -5
  62. snowflake/cli/plugins/snowpark/models.py +6 -0
  63. snowflake/cli/plugins/sql/commands.py +3 -5
  64. snowflake/cli/plugins/sql/manager.py +1 -1
  65. snowflake/cli/plugins/stage/commands.py +2 -2
  66. snowflake/cli/plugins/stage/diff.py +4 -2
  67. snowflake/cli/plugins/stage/manager.py +290 -86
  68. snowflake/cli/plugins/streamlit/commands.py +20 -6
  69. snowflake/cli/plugins/streamlit/manager.py +29 -27
  70. snowflake/cli/plugins/workspace/__init__.py +13 -0
  71. snowflake/cli/plugins/workspace/commands.py +35 -0
  72. snowflake/cli/plugins/workspace/plugin_spec.py +30 -0
  73. snowflake/cli/templates/default_snowpark/app/__init__.py +0 -13
  74. snowflake/cli/templates/default_snowpark/app/common.py +0 -15
  75. snowflake/cli/templates/default_snowpark/app/functions.py +0 -14
  76. snowflake/cli/templates/default_snowpark/app/procedures.py +0 -14
  77. snowflake/cli/templates/default_streamlit/common/hello.py +0 -15
  78. snowflake/cli/templates/default_streamlit/pages/my_page.py +0 -14
  79. snowflake/cli/templates/default_streamlit/streamlit_app.py +0 -14
  80. {snowflake_cli_labs-2.6.1.dist-info → snowflake_cli_labs-2.7.0rc1.dist-info}/METADATA +7 -6
  81. {snowflake_cli_labs-2.6.1.dist-info → snowflake_cli_labs-2.7.0rc1.dist-info}/RECORD +84 -64
  82. {snowflake_cli_labs-2.6.1.dist-info → snowflake_cli_labs-2.7.0rc1.dist-info}/WHEEL +0 -0
  83. {snowflake_cli_labs-2.6.1.dist-info → snowflake_cli_labs-2.7.0rc1.dist-info}/entry_points.txt +0 -0
  84. {snowflake_cli_labs-2.6.1.dist-info → snowflake_cli_labs-2.7.0rc1.dist-info}/licenses/LICENSE +0 -0
@@ -38,9 +38,7 @@ from snowflake.cli.api.constants import (
38
38
  DEPLOYMENT_STAGE,
39
39
  ObjectType,
40
40
  )
41
- from snowflake.cli.api.exceptions import (
42
- SecretsWithoutExternalAccessIntegrationError,
43
- )
41
+ from snowflake.cli.api.exceptions import SecretsWithoutExternalAccessIntegrationError
44
42
  from snowflake.cli.api.identifiers import FQN
45
43
  from snowflake.cli.api.output.types import (
46
44
  CollectionResult,
@@ -48,6 +46,7 @@ from snowflake.cli.api.output.types import (
48
46
  MessageResult,
49
47
  SingleQueryResult,
50
48
  )
49
+ from snowflake.cli.api.project.project_verification import assert_project_type
51
50
  from snowflake.cli.api.project.schemas.snowpark.callable import (
52
51
  FunctionSchema,
53
52
  ProcedureSchema,
@@ -68,7 +67,8 @@ from snowflake.cli.plugins.object.commands import (
68
67
  from snowflake.cli.plugins.object.manager import ObjectManager
69
68
  from snowflake.cli.plugins.snowpark import package_utils
70
69
  from snowflake.cli.plugins.snowpark.common import (
71
- build_udf_sproc_identifier,
70
+ FunctionOrProcedure,
71
+ UdfSprocIdentifier,
72
72
  check_if_replace_is_required,
73
73
  )
74
74
  from snowflake.cli.plugins.snowpark.manager import FunctionManager, ProcedureManager
@@ -116,7 +116,7 @@ add_init_command(app, project_type="Snowpark", template="default_snowpark")
116
116
 
117
117
 
118
118
  @app.command("deploy", requires_connection=True)
119
- @with_project_definition("snowpark")
119
+ @with_project_definition()
120
120
  def deploy(
121
121
  replace: bool = ReplaceOption(
122
122
  help="Replaces procedure or function, even if no detected changes to metadata"
@@ -128,6 +128,9 @@ def deploy(
128
128
  By default, if any of the objects exist already the commands will fail unless `--replace` flag is provided.
129
129
  All deployed objects use the same artifact which is deployed only once.
130
130
  """
131
+
132
+ assert_project_type("snowpark")
133
+
131
134
  snowpark = cli_context.project_definition.snowpark
132
135
  paths = SnowparkPackagePaths.for_snowpark_project(
133
136
  project_root=SecurePath(cli_context.project_root),
@@ -218,7 +221,7 @@ def deploy(
218
221
 
219
222
 
220
223
  def _assert_object_definitions_are_correct(
221
- object_type, object_definitions: List[FunctionSchema | ProcedureSchema]
224
+ object_type, object_definitions: List[FunctionOrProcedure]
222
225
  ):
223
226
  for definition in object_definitions:
224
227
  database = definition.database
@@ -237,14 +240,14 @@ def _assert_object_definitions_are_correct(
237
240
 
238
241
  def _find_existing_objects(
239
242
  object_type: ObjectType,
240
- objects: List[Dict],
243
+ objects: List[FunctionOrProcedure],
241
244
  om: ObjectManager,
242
245
  ):
243
246
  existing_objects = {}
244
247
  for object_definition in objects:
245
- identifier = build_udf_sproc_identifier(
246
- object_definition, om, include_parameter_names=False
247
- )
248
+ identifier = UdfSprocIdentifier.from_definition(
249
+ object_definition
250
+ ).identifier_with_arg_types
248
251
  try:
249
252
  current_state = om.describe(
250
253
  object_type=object_type.value.sf_name,
@@ -293,50 +296,52 @@ def get_app_stage_path(stage_name: Optional[str], project_name: str) -> str:
293
296
  def _deploy_single_object(
294
297
  manager: FunctionManager | ProcedureManager,
295
298
  object_type: ObjectType,
296
- object_definition: FunctionSchema | ProcedureSchema,
299
+ object_definition: FunctionOrProcedure,
297
300
  existing_objects: Dict[str, Dict],
298
301
  snowflake_dependencies: List[str],
299
302
  stage_artifact_path: str,
300
303
  ):
301
- identifier = build_udf_sproc_identifier(
302
- object_definition, manager, include_parameter_names=False
303
- )
304
- identifier_with_default_values = build_udf_sproc_identifier(
305
- object_definition,
306
- manager,
307
- include_parameter_names=True,
308
- include_default_values=True,
304
+
305
+ identifiers = UdfSprocIdentifier.from_definition(object_definition)
306
+
307
+ log.info(
308
+ "Deploying %s: %s", object_type, identifiers.identifier_with_arg_names_types
309
309
  )
310
- log.info("Deploying %s: %s", object_type, identifier_with_default_values)
311
310
 
312
311
  handler = object_definition.handler
313
312
  returns = object_definition.returns
314
313
  imports = object_definition.imports
315
314
  external_access_integrations = object_definition.external_access_integrations
315
+ runtime_ver = object_definition.runtime
316
+ execute_as_caller = None
317
+ if object_type == ObjectType.PROCEDURE:
318
+ execute_as_caller = object_definition.execute_as_caller
316
319
  replace_object = False
317
320
 
318
- object_exists = identifier in existing_objects
321
+ object_exists = identifiers.identifier_with_arg_types in existing_objects
319
322
  if object_exists:
320
323
  replace_object = check_if_replace_is_required(
321
324
  object_type=object_type,
322
- current_state=existing_objects[identifier],
325
+ current_state=existing_objects[identifiers.identifier_with_arg_types],
323
326
  handler=handler,
324
327
  return_type=returns,
325
328
  snowflake_dependencies=snowflake_dependencies,
326
329
  external_access_integrations=external_access_integrations,
327
330
  imports=imports,
328
331
  stage_artifact_file=stage_artifact_path,
332
+ runtime_ver=runtime_ver,
333
+ execute_as_caller=execute_as_caller,
329
334
  )
330
335
 
331
336
  if object_exists and not replace_object:
332
337
  return {
333
- "object": identifier_with_default_values,
338
+ "object": identifiers.identifier_with_arg_names_types_defaults,
334
339
  "type": str(object_type),
335
340
  "status": "packages updated",
336
341
  }
337
342
 
338
343
  create_or_replace_kwargs = {
339
- "identifier": identifier_with_default_values,
344
+ "identifier": identifiers,
340
345
  "handler": handler,
341
346
  "return_type": returns,
342
347
  "artifact_file": stage_artifact_path,
@@ -354,7 +359,7 @@ def _deploy_single_object(
354
359
 
355
360
  status = "created" if not object_exists else "definition updated"
356
361
  return {
357
- "object": identifier_with_default_values,
362
+ "object": identifiers.identifier_with_arg_names_types_defaults,
358
363
  "type": str(object_type),
359
364
  "status": status,
360
365
  }
@@ -379,7 +384,7 @@ def _read_snowflake_requrements_file(file_path: SecurePath):
379
384
 
380
385
 
381
386
  @app.command("build", requires_connection=True)
382
- @with_project_definition("snowpark")
387
+ @with_project_definition()
383
388
  def build(
384
389
  ignore_anaconda: bool = IgnoreAnacondaOption,
385
390
  allow_shared_libraries: bool = AllowSharedLibrariesOption,
@@ -396,6 +401,9 @@ def build(
396
401
  Builds the Snowpark project as a `.zip` archive that can be used by `deploy` command.
397
402
  The archive is built using only the `src` directory specified in the project file.
398
403
  """
404
+
405
+ assert_project_type("snowpark")
406
+
399
407
  if not deprecated_check_anaconda_for_pypi_deps:
400
408
  ignore_anaconda = True
401
409
  snowpark_paths = SnowparkPackagePaths.for_snowpark_project(
@@ -15,11 +15,14 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import re
18
- from typing import Dict, List, Optional, Set
18
+ from typing import Dict, List, Optional, Set, Union
19
19
 
20
20
  from snowflake.cli.api.constants import ObjectType
21
21
  from snowflake.cli.api.identifiers import FQN
22
- from snowflake.cli.api.project.schemas.snowpark.argument import Argument
22
+ from snowflake.cli.api.project.schemas.snowpark.callable import (
23
+ FunctionSchema,
24
+ ProcedureSchema,
25
+ )
23
26
  from snowflake.cli.api.sql_execution import SqlExecutionMixin
24
27
  from snowflake.cli.plugins.snowpark.models import Requirement
25
28
  from snowflake.cli.plugins.snowpark.package_utils import (
@@ -28,6 +31,7 @@ from snowflake.cli.plugins.snowpark.package_utils import (
28
31
  from snowflake.connector.cursor import SnowflakeCursor
29
32
 
30
33
  DEFAULT_RUNTIME = "3.8"
34
+ FunctionOrProcedure = Union[FunctionSchema, ProcedureSchema]
31
35
 
32
36
 
33
37
  def check_if_replace_is_required(
@@ -39,6 +43,8 @@ def check_if_replace_is_required(
39
43
  external_access_integrations: List[str],
40
44
  imports: List[str],
41
45
  stage_artifact_file: str,
46
+ runtime_ver: Optional[str] = None,
47
+ execute_as_caller: Optional[bool] = None,
42
48
  ) -> bool:
43
49
  import logging
44
50
 
@@ -78,6 +84,22 @@ def check_if_replace_is_required(
78
84
  return True
79
85
 
80
86
  if _compare_imports(resource_json, imports, stage_artifact_file):
87
+ log.info("Imports do not match. Replacing the %s", object_type)
88
+ return True
89
+
90
+ if runtime_ver is not None and runtime_ver != resource_json.get(
91
+ "runtime_version", "RUNTIME_NOT_SET"
92
+ ):
93
+ log.info("Runtime versions do not match. Replacing the %s", object_type)
94
+ return True
95
+
96
+ if execute_as_caller is not None and (
97
+ resource_json.get("execute as", "OWNER")
98
+ != ("CALLER" if execute_as_caller else "OWNER")
99
+ ):
100
+ log.info(
101
+ "Execute as caller settings do not match. Replacing the %s", object_type
102
+ )
81
103
  return True
82
104
 
83
105
  return False
@@ -150,7 +172,7 @@ class SnowparkObjectManager(SqlExecutionMixin):
150
172
 
151
173
  def create_query(
152
174
  self,
153
- identifier: str,
175
+ identifier: UdfSprocIdentifier,
154
176
  return_type: str,
155
177
  handler: str,
156
178
  artifact_file: str,
@@ -166,7 +188,7 @@ class SnowparkObjectManager(SqlExecutionMixin):
166
188
  packages_list = ",".join(f"'{p}'" for p in packages)
167
189
 
168
190
  query = [
169
- f"create or replace {self._object_type.value.sf_name} {identifier}",
191
+ f"create or replace {self._object_type.value.sf_name} {identifier.identifier_for_sql}",
170
192
  f"copy grants",
171
193
  f"returns {return_type}",
172
194
  "language python",
@@ -198,30 +220,69 @@ def _is_signature_type_a_string(sig_type: str) -> bool:
198
220
  return sig_type.lower() in ["string", "varchar"]
199
221
 
200
222
 
201
- def build_udf_sproc_identifier(
202
- udf_sproc,
203
- slq_exec_mixin,
204
- include_parameter_names,
205
- include_default_values=False,
206
- ):
207
- def format_arg(arg: Argument):
208
- result = f"{arg.arg_type}"
209
- if include_parameter_names:
210
- result = f"{arg.name} {result}"
211
- if include_default_values and arg.default:
212
- val = f"{arg.default}"
213
- if _is_signature_type_a_string(arg.arg_type):
214
- val = f"'{val}'"
215
- result += f" default {val}"
216
- return result
217
-
218
- if udf_sproc.signature and udf_sproc.signature != "null":
219
- arguments = ", ".join(format_arg(arg) for arg in udf_sproc.signature)
220
- else:
221
- arguments = ""
223
+ class UdfSprocIdentifier:
224
+ def __init__(self, identifier: FQN, arg_names, arg_types, arg_defaults):
225
+ self._identifier = identifier
226
+ self._arg_names = arg_names
227
+ self._arg_types = arg_types
228
+ self._arg_defaults = arg_defaults
229
+
230
+ def _identifier_from_signature(self, sig: List[str], for_sql: bool = False):
231
+ signature = self._comma_join(sig)
232
+ id_ = self._identifier.sql_identifier if for_sql else self._identifier
233
+ return f"{id_}({signature})"
222
234
 
223
- name = FQN.from_identifier_model(udf_sproc).using_context().identifier
224
- return f"{name}({arguments})"
235
+ @staticmethod
236
+ def _comma_join(*args):
237
+ return ", ".join(*args)
238
+
239
+ @property
240
+ def identifier_with_arg_names(self):
241
+ return self._identifier_from_signature(self._arg_names)
242
+
243
+ @property
244
+ def identifier_with_arg_types(self):
245
+ return self._identifier_from_signature(self._arg_types)
246
+
247
+ @property
248
+ def identifier_with_arg_names_types(self):
249
+ sig = [f"{n} {t}" for n, t in zip(self._arg_names, self._arg_types)]
250
+ return self._identifier_from_signature(sig)
251
+
252
+ @property
253
+ def identifier_with_arg_names_types_defaults(self):
254
+ return self._identifier_from_signature(self._full_signature())
255
+
256
+ def _full_signature(self):
257
+ sig = []
258
+ for name, _type, _default in zip(
259
+ self._arg_names, self._arg_types, self._arg_defaults
260
+ ):
261
+ s = f"{name} {_type}"
262
+ if _default:
263
+ if _is_signature_type_a_string(_type):
264
+ _default = f"'{_default}'"
265
+ s += f" default {_default}"
266
+ sig.append(s)
267
+ return sig
268
+
269
+ @property
270
+ def identifier_for_sql(self):
271
+ return self._identifier_from_signature(self._full_signature(), for_sql=True)
272
+
273
+ @classmethod
274
+ def from_definition(cls, udf_sproc: FunctionOrProcedure):
275
+ names = []
276
+ types = []
277
+ defaults = []
278
+ if udf_sproc.signature and udf_sproc.signature != "null":
279
+ for arg in udf_sproc.signature:
280
+ names.append(arg.name)
281
+ types.append(arg.arg_type)
282
+ defaults.append(arg.default)
283
+
284
+ identifier = FQN.from_identifier_model(udf_sproc).using_context()
285
+ return cls(identifier, names, types, defaults)
225
286
 
226
287
 
227
288
  def _compare_imports(
@@ -18,7 +18,10 @@ import logging
18
18
  from typing import Dict, List, Optional
19
19
 
20
20
  from snowflake.cli.api.constants import ObjectType
21
- from snowflake.cli.plugins.snowpark.common import SnowparkObjectManager
21
+ from snowflake.cli.plugins.snowpark.common import (
22
+ SnowparkObjectManager,
23
+ UdfSprocIdentifier,
24
+ )
22
25
  from snowflake.connector.cursor import SnowflakeCursor
23
26
 
24
27
  log = logging.getLogger(__name__)
@@ -35,7 +38,7 @@ class FunctionManager(SnowparkObjectManager):
35
38
 
36
39
  def create_or_replace(
37
40
  self,
38
- identifier: str,
41
+ identifier: UdfSprocIdentifier,
39
42
  return_type: str,
40
43
  handler: str,
41
44
  artifact_file: str,
@@ -45,7 +48,11 @@ class FunctionManager(SnowparkObjectManager):
45
48
  secrets: Optional[Dict[str, str]] = None,
46
49
  runtime: Optional[str] = None,
47
50
  ) -> SnowflakeCursor:
48
- log.debug("Creating function %s using @%s", identifier, artifact_file)
51
+ log.debug(
52
+ "Creating function %s using @%s",
53
+ identifier.identifier_with_arg_names_types_defaults,
54
+ artifact_file,
55
+ )
49
56
  query = self.create_query(
50
57
  identifier,
51
58
  return_type,
@@ -71,7 +78,7 @@ class ProcedureManager(SnowparkObjectManager):
71
78
 
72
79
  def create_or_replace(
73
80
  self,
74
- identifier: str,
81
+ identifier: UdfSprocIdentifier,
75
82
  return_type: str,
76
83
  handler: str,
77
84
  artifact_file: str,
@@ -82,7 +89,11 @@ class ProcedureManager(SnowparkObjectManager):
82
89
  runtime: Optional[str] = None,
83
90
  execute_as_caller: bool = False,
84
91
  ) -> SnowflakeCursor:
85
- log.debug("Creating procedure %s using @%s", identifier, artifact_file)
92
+ log.debug(
93
+ "Creating procedure %s using @%s",
94
+ identifier.identifier_with_arg_names_types_defaults,
95
+ artifact_file,
96
+ )
86
97
  query = self.create_query(
87
98
  identifier,
88
99
  return_type,
@@ -33,6 +33,10 @@ class YesNoAsk(Enum):
33
33
  class Requirement(requirement.Requirement):
34
34
  extra_pattern = re.compile("'([^']*)'")
35
35
 
36
+ def __init__(self, *args, **kwargs):
37
+ super().__init__(*args, **kwargs)
38
+ self.package_name = None
39
+
36
40
  @classmethod
37
41
  def parse_line(cls, line: str) -> Requirement:
38
42
  if len(line_elements := line.split(";")) > 1:
@@ -44,6 +48,8 @@ class Requirement(requirement.Requirement):
44
48
  if "extra" in element and (extras := cls.extra_pattern.search(element)):
45
49
  result.extras.extend(extras.groups())
46
50
 
51
+ result.package_name = result.name
52
+
47
53
  if result.uri and not result.name:
48
54
  result.name = get_package_name(result.uri)
49
55
  result.name = cls.standardize_name(result.name)
@@ -21,6 +21,7 @@ import typer
21
21
  from snowflake.cli.api.commands.decorators import with_project_definition
22
22
  from snowflake.cli.api.commands.flags import (
23
23
  parse_key_value_variables,
24
+ variables_option,
24
25
  )
25
26
  from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
26
27
  from snowflake.cli.api.output.types import CommandResult, MultipleResults, QueryResult
@@ -55,11 +56,8 @@ def execute_sql(
55
56
  "-i",
56
57
  help="Read the query from standard input. Use it when piping input to this command.",
57
58
  ),
58
- data_override: List[str] = typer.Option(
59
- None,
60
- "--variable",
61
- "-D",
62
- help="String in format of key=value. If provided the SQL content will "
59
+ data_override: List[str] = variables_option(
60
+ "String in format of key=value. If provided the SQL content will "
63
61
  "be treated as template and rendered using provided data.",
64
62
  ),
65
63
  **options,
@@ -22,9 +22,9 @@ from typing import Dict, Iterable, List, Tuple
22
22
 
23
23
  from click import ClickException, UsageError
24
24
  from jinja2 import UndefinedError
25
+ from snowflake.cli.api.rendering.sql_templates import snowflake_sql_jinja_render
25
26
  from snowflake.cli.api.secure_path import UNLIMITED, SecurePath
26
27
  from snowflake.cli.api.sql_execution import SqlExecutionMixin, VerboseCursor
27
- from snowflake.cli.api.utils.rendering import snowflake_sql_jinja_render
28
28
  from snowflake.cli.plugins.sql.snowsql_templating import transpile_snowsql_templates
29
29
  from snowflake.connector.cursor import SnowflakeCursor
30
30
  from snowflake.connector.util_text import split_statements
@@ -23,9 +23,9 @@ import click
23
23
  import typer
24
24
  from snowflake.cli.api.cli_global_context import cli_context
25
25
  from snowflake.cli.api.commands.flags import (
26
+ ExecuteVariablesOption,
26
27
  OnErrorOption,
27
28
  PatternOption,
28
- VariablesOption,
29
29
  like_option,
30
30
  )
31
31
  from snowflake.cli.api.commands.snow_typer import SnowTyperFactory
@@ -201,7 +201,7 @@ def execute(
201
201
  show_default=False,
202
202
  ),
203
203
  on_error: OnErrorType = OnErrorOption,
204
- variables: Optional[List[str]] = VariablesOption,
204
+ variables: Optional[List[str]] = ExecuteVariablesOption,
205
205
  **options,
206
206
  ):
207
207
  """
@@ -72,10 +72,12 @@ class DiffResult:
72
72
  }
73
73
 
74
74
 
75
- def is_valid_md5sum(checksum: str) -> bool:
75
+ def is_valid_md5sum(checksum: Optional[str]) -> bool:
76
76
  """
77
77
  Could the provided hexadecimal checksum represent a valid md5sum?
78
78
  """
79
+ if checksum is None:
80
+ return False
79
81
  return re.match(MD5SUM_REGEX, checksum) is not None
80
82
 
81
83
 
@@ -131,7 +133,7 @@ def strip_stage_name(path: str) -> StagePath:
131
133
  return StagePath(*path.split("/")[1:])
132
134
 
133
135
 
134
- def build_md5_map(list_stage_cursor: DictCursor) -> Dict[StagePath, str]:
136
+ def build_md5_map(list_stage_cursor: DictCursor) -> Dict[StagePath, Optional[str]]:
135
137
  """
136
138
  Returns a mapping of relative stage paths to their md5sums.
137
139
  """