snowflake-ml-python 1.6.2__py3-none-any.whl → 1.6.4__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 (262) hide show
  1. snowflake/cortex/__init__.py +4 -0
  2. snowflake/cortex/_classify_text.py +2 -2
  3. snowflake/cortex/_embed_text_1024.py +37 -0
  4. snowflake/cortex/_embed_text_768.py +37 -0
  5. snowflake/cortex/_extract_answer.py +2 -2
  6. snowflake/cortex/_sentiment.py +2 -2
  7. snowflake/cortex/_summarize.py +2 -2
  8. snowflake/cortex/_translate.py +2 -2
  9. snowflake/cortex/_util.py +4 -4
  10. snowflake/ml/_internal/env_utils.py +5 -5
  11. snowflake/ml/_internal/exceptions/error_codes.py +2 -0
  12. snowflake/ml/_internal/utils/db_utils.py +50 -0
  13. snowflake/ml/_internal/utils/service_logger.py +63 -0
  14. snowflake/ml/_internal/utils/sql_identifier.py +25 -1
  15. snowflake/ml/data/_internal/arrow_ingestor.py +1 -11
  16. snowflake/ml/data/ingestor_utils.py +20 -10
  17. snowflake/ml/feature_store/access_manager.py +3 -3
  18. snowflake/ml/feature_store/feature_store.py +19 -2
  19. snowflake/ml/feature_store/feature_view.py +82 -28
  20. snowflake/ml/fileset/stage_fs.py +2 -1
  21. snowflake/ml/lineage/lineage_node.py +7 -2
  22. snowflake/ml/model/__init__.py +1 -2
  23. snowflake/ml/model/_client/model/model_version_impl.py +78 -9
  24. snowflake/ml/model/_client/ops/model_ops.py +89 -7
  25. snowflake/ml/model/_client/ops/service_ops.py +200 -91
  26. snowflake/ml/model/_client/service/model_deployment_spec.py +4 -0
  27. snowflake/ml/model/_client/service/model_deployment_spec_schema.py +1 -0
  28. snowflake/ml/model/_client/sql/_base.py +5 -0
  29. snowflake/ml/model/_client/sql/model.py +1 -0
  30. snowflake/ml/model/_client/sql/model_version.py +9 -5
  31. snowflake/ml/model/_client/sql/service.py +35 -13
  32. snowflake/ml/model/_model_composer/model_composer.py +11 -41
  33. snowflake/ml/model/_model_composer/model_manifest/model_manifest.py +29 -4
  34. snowflake/ml/model/_packager/model_env/model_env.py +4 -38
  35. snowflake/ml/model/_packager/model_handlers/_utils.py +106 -32
  36. snowflake/ml/model/_packager/model_handlers/catboost.py +26 -27
  37. snowflake/ml/model/_packager/model_handlers/huggingface_pipeline.py +3 -3
  38. snowflake/ml/model/_packager/model_handlers/lightgbm.py +21 -6
  39. snowflake/ml/model/_packager/model_handlers/mlflow.py +3 -5
  40. snowflake/ml/model/_packager/model_handlers/model_objective_utils.py +111 -58
  41. snowflake/ml/model/_packager/model_handlers/sentence_transformers.py +15 -8
  42. snowflake/ml/model/_packager/model_handlers/sklearn.py +50 -66
  43. snowflake/ml/model/_packager/model_handlers/snowmlmodel.py +36 -17
  44. snowflake/ml/model/_packager/model_handlers/xgboost.py +22 -7
  45. snowflake/ml/model/_packager/model_meta/model_meta.py +16 -45
  46. snowflake/ml/model/_packager/model_meta/model_meta_schema.py +1 -6
  47. snowflake/ml/model/_packager/model_packager.py +14 -10
  48. snowflake/ml/model/_packager/model_runtime/model_runtime.py +11 -0
  49. snowflake/ml/model/_signatures/snowpark_handler.py +3 -2
  50. snowflake/ml/model/type_hints.py +11 -152
  51. snowflake/ml/modeling/_internal/snowpark_implementations/distributed_hpo_trainer.py +0 -2
  52. snowflake/ml/modeling/_internal/snowpark_implementations/snowpark_trainer.py +17 -6
  53. snowflake/ml/modeling/_internal/snowpark_implementations/xgboost_external_memory_trainer.py +0 -1
  54. snowflake/ml/modeling/calibration/calibrated_classifier_cv.py +1 -0
  55. snowflake/ml/modeling/cluster/affinity_propagation.py +1 -0
  56. snowflake/ml/modeling/cluster/agglomerative_clustering.py +1 -0
  57. snowflake/ml/modeling/cluster/birch.py +1 -0
  58. snowflake/ml/modeling/cluster/bisecting_k_means.py +1 -0
  59. snowflake/ml/modeling/cluster/dbscan.py +1 -0
  60. snowflake/ml/modeling/cluster/feature_agglomeration.py +1 -0
  61. snowflake/ml/modeling/cluster/k_means.py +1 -0
  62. snowflake/ml/modeling/cluster/mean_shift.py +1 -0
  63. snowflake/ml/modeling/cluster/mini_batch_k_means.py +1 -0
  64. snowflake/ml/modeling/cluster/optics.py +1 -0
  65. snowflake/ml/modeling/cluster/spectral_biclustering.py +1 -0
  66. snowflake/ml/modeling/cluster/spectral_clustering.py +1 -0
  67. snowflake/ml/modeling/cluster/spectral_coclustering.py +1 -0
  68. snowflake/ml/modeling/compose/column_transformer.py +1 -0
  69. snowflake/ml/modeling/compose/transformed_target_regressor.py +1 -0
  70. snowflake/ml/modeling/covariance/elliptic_envelope.py +1 -0
  71. snowflake/ml/modeling/covariance/empirical_covariance.py +1 -0
  72. snowflake/ml/modeling/covariance/graphical_lasso.py +1 -0
  73. snowflake/ml/modeling/covariance/graphical_lasso_cv.py +1 -0
  74. snowflake/ml/modeling/covariance/ledoit_wolf.py +1 -0
  75. snowflake/ml/modeling/covariance/min_cov_det.py +1 -0
  76. snowflake/ml/modeling/covariance/oas.py +1 -0
  77. snowflake/ml/modeling/covariance/shrunk_covariance.py +1 -0
  78. snowflake/ml/modeling/decomposition/dictionary_learning.py +1 -0
  79. snowflake/ml/modeling/decomposition/factor_analysis.py +1 -0
  80. snowflake/ml/modeling/decomposition/fast_ica.py +1 -0
  81. snowflake/ml/modeling/decomposition/incremental_pca.py +1 -0
  82. snowflake/ml/modeling/decomposition/kernel_pca.py +1 -0
  83. snowflake/ml/modeling/decomposition/mini_batch_dictionary_learning.py +1 -0
  84. snowflake/ml/modeling/decomposition/mini_batch_sparse_pca.py +1 -0
  85. snowflake/ml/modeling/decomposition/pca.py +1 -0
  86. snowflake/ml/modeling/decomposition/sparse_pca.py +1 -0
  87. snowflake/ml/modeling/decomposition/truncated_svd.py +1 -0
  88. snowflake/ml/modeling/discriminant_analysis/linear_discriminant_analysis.py +1 -0
  89. snowflake/ml/modeling/discriminant_analysis/quadratic_discriminant_analysis.py +1 -0
  90. snowflake/ml/modeling/ensemble/ada_boost_classifier.py +1 -0
  91. snowflake/ml/modeling/ensemble/ada_boost_regressor.py +1 -0
  92. snowflake/ml/modeling/ensemble/bagging_classifier.py +1 -0
  93. snowflake/ml/modeling/ensemble/bagging_regressor.py +1 -0
  94. snowflake/ml/modeling/ensemble/extra_trees_classifier.py +1 -0
  95. snowflake/ml/modeling/ensemble/extra_trees_regressor.py +1 -0
  96. snowflake/ml/modeling/ensemble/gradient_boosting_classifier.py +1 -0
  97. snowflake/ml/modeling/ensemble/gradient_boosting_regressor.py +1 -0
  98. snowflake/ml/modeling/ensemble/hist_gradient_boosting_classifier.py +1 -0
  99. snowflake/ml/modeling/ensemble/hist_gradient_boosting_regressor.py +1 -0
  100. snowflake/ml/modeling/ensemble/isolation_forest.py +1 -0
  101. snowflake/ml/modeling/ensemble/random_forest_classifier.py +1 -0
  102. snowflake/ml/modeling/ensemble/random_forest_regressor.py +1 -0
  103. snowflake/ml/modeling/ensemble/stacking_regressor.py +1 -0
  104. snowflake/ml/modeling/ensemble/voting_classifier.py +1 -0
  105. snowflake/ml/modeling/ensemble/voting_regressor.py +1 -0
  106. snowflake/ml/modeling/feature_selection/generic_univariate_select.py +1 -0
  107. snowflake/ml/modeling/feature_selection/select_fdr.py +1 -0
  108. snowflake/ml/modeling/feature_selection/select_fpr.py +1 -0
  109. snowflake/ml/modeling/feature_selection/select_fwe.py +1 -0
  110. snowflake/ml/modeling/feature_selection/select_k_best.py +1 -0
  111. snowflake/ml/modeling/feature_selection/select_percentile.py +1 -0
  112. snowflake/ml/modeling/feature_selection/sequential_feature_selector.py +1 -0
  113. snowflake/ml/modeling/feature_selection/variance_threshold.py +1 -0
  114. snowflake/ml/modeling/gaussian_process/gaussian_process_classifier.py +1 -0
  115. snowflake/ml/modeling/gaussian_process/gaussian_process_regressor.py +1 -0
  116. snowflake/ml/modeling/impute/iterative_imputer.py +1 -0
  117. snowflake/ml/modeling/impute/knn_imputer.py +1 -0
  118. snowflake/ml/modeling/impute/missing_indicator.py +1 -0
  119. snowflake/ml/modeling/kernel_approximation/additive_chi2_sampler.py +1 -0
  120. snowflake/ml/modeling/kernel_approximation/nystroem.py +1 -0
  121. snowflake/ml/modeling/kernel_approximation/polynomial_count_sketch.py +1 -0
  122. snowflake/ml/modeling/kernel_approximation/rbf_sampler.py +1 -0
  123. snowflake/ml/modeling/kernel_approximation/skewed_chi2_sampler.py +1 -0
  124. snowflake/ml/modeling/kernel_ridge/kernel_ridge.py +1 -0
  125. snowflake/ml/modeling/lightgbm/lgbm_classifier.py +1 -0
  126. snowflake/ml/modeling/lightgbm/lgbm_regressor.py +1 -0
  127. snowflake/ml/modeling/linear_model/ard_regression.py +1 -0
  128. snowflake/ml/modeling/linear_model/bayesian_ridge.py +1 -0
  129. snowflake/ml/modeling/linear_model/elastic_net.py +1 -0
  130. snowflake/ml/modeling/linear_model/elastic_net_cv.py +1 -0
  131. snowflake/ml/modeling/linear_model/gamma_regressor.py +1 -0
  132. snowflake/ml/modeling/linear_model/huber_regressor.py +1 -0
  133. snowflake/ml/modeling/linear_model/lars.py +1 -0
  134. snowflake/ml/modeling/linear_model/lars_cv.py +1 -0
  135. snowflake/ml/modeling/linear_model/lasso.py +1 -0
  136. snowflake/ml/modeling/linear_model/lasso_cv.py +1 -0
  137. snowflake/ml/modeling/linear_model/lasso_lars.py +1 -0
  138. snowflake/ml/modeling/linear_model/lasso_lars_cv.py +1 -0
  139. snowflake/ml/modeling/linear_model/lasso_lars_ic.py +1 -0
  140. snowflake/ml/modeling/linear_model/linear_regression.py +1 -0
  141. snowflake/ml/modeling/linear_model/logistic_regression.py +1 -0
  142. snowflake/ml/modeling/linear_model/logistic_regression_cv.py +1 -0
  143. snowflake/ml/modeling/linear_model/multi_task_elastic_net.py +1 -0
  144. snowflake/ml/modeling/linear_model/multi_task_elastic_net_cv.py +1 -0
  145. snowflake/ml/modeling/linear_model/multi_task_lasso.py +1 -0
  146. snowflake/ml/modeling/linear_model/multi_task_lasso_cv.py +1 -0
  147. snowflake/ml/modeling/linear_model/orthogonal_matching_pursuit.py +1 -0
  148. snowflake/ml/modeling/linear_model/passive_aggressive_classifier.py +1 -0
  149. snowflake/ml/modeling/linear_model/passive_aggressive_regressor.py +1 -0
  150. snowflake/ml/modeling/linear_model/perceptron.py +1 -0
  151. snowflake/ml/modeling/linear_model/poisson_regressor.py +1 -0
  152. snowflake/ml/modeling/linear_model/ransac_regressor.py +1 -0
  153. snowflake/ml/modeling/linear_model/ridge.py +1 -0
  154. snowflake/ml/modeling/linear_model/ridge_classifier.py +1 -0
  155. snowflake/ml/modeling/linear_model/ridge_classifier_cv.py +1 -0
  156. snowflake/ml/modeling/linear_model/ridge_cv.py +1 -0
  157. snowflake/ml/modeling/linear_model/sgd_classifier.py +1 -0
  158. snowflake/ml/modeling/linear_model/sgd_one_class_svm.py +1 -0
  159. snowflake/ml/modeling/linear_model/sgd_regressor.py +1 -0
  160. snowflake/ml/modeling/linear_model/theil_sen_regressor.py +1 -0
  161. snowflake/ml/modeling/linear_model/tweedie_regressor.py +1 -0
  162. snowflake/ml/modeling/manifold/isomap.py +1 -0
  163. snowflake/ml/modeling/manifold/mds.py +1 -0
  164. snowflake/ml/modeling/manifold/spectral_embedding.py +1 -0
  165. snowflake/ml/modeling/manifold/tsne.py +1 -0
  166. snowflake/ml/modeling/metrics/metrics_utils.py +2 -2
  167. snowflake/ml/modeling/metrics/ranking.py +0 -3
  168. snowflake/ml/modeling/metrics/regression.py +0 -3
  169. snowflake/ml/modeling/mixture/bayesian_gaussian_mixture.py +1 -0
  170. snowflake/ml/modeling/mixture/gaussian_mixture.py +1 -0
  171. snowflake/ml/modeling/multiclass/one_vs_one_classifier.py +1 -0
  172. snowflake/ml/modeling/multiclass/one_vs_rest_classifier.py +1 -0
  173. snowflake/ml/modeling/multiclass/output_code_classifier.py +1 -0
  174. snowflake/ml/modeling/naive_bayes/bernoulli_nb.py +1 -0
  175. snowflake/ml/modeling/naive_bayes/categorical_nb.py +1 -0
  176. snowflake/ml/modeling/naive_bayes/complement_nb.py +1 -0
  177. snowflake/ml/modeling/naive_bayes/gaussian_nb.py +1 -0
  178. snowflake/ml/modeling/naive_bayes/multinomial_nb.py +1 -0
  179. snowflake/ml/modeling/neighbors/k_neighbors_classifier.py +1 -0
  180. snowflake/ml/modeling/neighbors/k_neighbors_regressor.py +1 -0
  181. snowflake/ml/modeling/neighbors/kernel_density.py +1 -0
  182. snowflake/ml/modeling/neighbors/local_outlier_factor.py +1 -0
  183. snowflake/ml/modeling/neighbors/nearest_centroid.py +1 -0
  184. snowflake/ml/modeling/neighbors/nearest_neighbors.py +1 -0
  185. snowflake/ml/modeling/neighbors/neighborhood_components_analysis.py +1 -0
  186. snowflake/ml/modeling/neighbors/radius_neighbors_classifier.py +1 -0
  187. snowflake/ml/modeling/neighbors/radius_neighbors_regressor.py +1 -0
  188. snowflake/ml/modeling/neural_network/bernoulli_rbm.py +1 -0
  189. snowflake/ml/modeling/neural_network/mlp_classifier.py +1 -0
  190. snowflake/ml/modeling/neural_network/mlp_regressor.py +1 -0
  191. snowflake/ml/modeling/pipeline/pipeline.py +0 -1
  192. snowflake/ml/modeling/preprocessing/polynomial_features.py +1 -0
  193. snowflake/ml/modeling/semi_supervised/label_propagation.py +1 -0
  194. snowflake/ml/modeling/semi_supervised/label_spreading.py +1 -0
  195. snowflake/ml/modeling/svm/linear_svc.py +1 -0
  196. snowflake/ml/modeling/svm/linear_svr.py +1 -0
  197. snowflake/ml/modeling/svm/nu_svc.py +1 -0
  198. snowflake/ml/modeling/svm/nu_svr.py +1 -0
  199. snowflake/ml/modeling/svm/svc.py +1 -0
  200. snowflake/ml/modeling/svm/svr.py +1 -0
  201. snowflake/ml/modeling/tree/decision_tree_classifier.py +1 -0
  202. snowflake/ml/modeling/tree/decision_tree_regressor.py +1 -0
  203. snowflake/ml/modeling/tree/extra_tree_classifier.py +1 -0
  204. snowflake/ml/modeling/tree/extra_tree_regressor.py +1 -0
  205. snowflake/ml/modeling/xgboost/xgb_classifier.py +1 -0
  206. snowflake/ml/modeling/xgboost/xgb_regressor.py +1 -0
  207. snowflake/ml/modeling/xgboost/xgbrf_classifier.py +1 -0
  208. snowflake/ml/modeling/xgboost/xgbrf_regressor.py +1 -0
  209. snowflake/ml/monitoring/_client/model_monitor.py +126 -0
  210. snowflake/ml/monitoring/_client/model_monitor_manager.py +361 -0
  211. snowflake/ml/monitoring/_client/model_monitor_version.py +1 -0
  212. snowflake/ml/monitoring/_client/monitor_sql_client.py +1335 -0
  213. snowflake/ml/monitoring/_client/queries/record_count.ssql +14 -0
  214. snowflake/ml/monitoring/_client/queries/rmse.ssql +28 -0
  215. snowflake/ml/monitoring/entities/model_monitor_config.py +28 -0
  216. snowflake/ml/monitoring/entities/model_monitor_interval.py +46 -0
  217. snowflake/ml/monitoring/entities/output_score_type.py +90 -0
  218. snowflake/ml/registry/_manager/model_manager.py +4 -4
  219. snowflake/ml/registry/registry.py +165 -6
  220. snowflake/ml/version.py +1 -1
  221. {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.4.dist-info}/METADATA +30 -9
  222. {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.4.dist-info}/RECORD +225 -249
  223. {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.4.dist-info}/WHEEL +1 -1
  224. snowflake/ml/_internal/container_services/image_registry/credential.py +0 -84
  225. snowflake/ml/_internal/container_services/image_registry/http_client.py +0 -127
  226. snowflake/ml/_internal/container_services/image_registry/imagelib.py +0 -400
  227. snowflake/ml/_internal/container_services/image_registry/registry_client.py +0 -212
  228. snowflake/ml/_internal/utils/log_stream_processor.py +0 -30
  229. snowflake/ml/_internal/utils/session_token_manager.py +0 -46
  230. snowflake/ml/_internal/utils/spcs_attribution_utils.py +0 -122
  231. snowflake/ml/_internal/utils/uri.py +0 -77
  232. snowflake/ml/model/_api.py +0 -568
  233. snowflake/ml/model/_deploy_client/image_builds/base_image_builder.py +0 -12
  234. snowflake/ml/model/_deploy_client/image_builds/client_image_builder.py +0 -249
  235. snowflake/ml/model/_deploy_client/image_builds/docker_context.py +0 -130
  236. snowflake/ml/model/_deploy_client/image_builds/gunicorn_run.sh +0 -36
  237. snowflake/ml/model/_deploy_client/image_builds/inference_server/main.py +0 -268
  238. snowflake/ml/model/_deploy_client/image_builds/server_image_builder.py +0 -215
  239. snowflake/ml/model/_deploy_client/image_builds/templates/dockerfile_template +0 -53
  240. snowflake/ml/model/_deploy_client/image_builds/templates/image_build_job_spec_template +0 -38
  241. snowflake/ml/model/_deploy_client/image_builds/templates/kaniko_shell_script_template +0 -105
  242. snowflake/ml/model/_deploy_client/snowservice/deploy.py +0 -611
  243. snowflake/ml/model/_deploy_client/snowservice/deploy_options.py +0 -116
  244. snowflake/ml/model/_deploy_client/snowservice/instance_types.py +0 -10
  245. snowflake/ml/model/_deploy_client/snowservice/templates/service_spec_template +0 -28
  246. snowflake/ml/model/_deploy_client/snowservice/templates/service_spec_template_with_model +0 -21
  247. snowflake/ml/model/_deploy_client/utils/constants.py +0 -48
  248. snowflake/ml/model/_deploy_client/utils/snowservice_client.py +0 -280
  249. snowflake/ml/model/_deploy_client/warehouse/deploy.py +0 -202
  250. snowflake/ml/model/_deploy_client/warehouse/infer_template.py +0 -99
  251. snowflake/ml/model/_packager/model_handlers/llm.py +0 -269
  252. snowflake/ml/model/_packager/model_meta/_core_requirements.py +0 -11
  253. snowflake/ml/model/deploy_platforms.py +0 -6
  254. snowflake/ml/model/models/llm.py +0 -106
  255. snowflake/ml/monitoring/monitor.py +0 -203
  256. snowflake/ml/registry/_initial_schema.py +0 -142
  257. snowflake/ml/registry/_schema.py +0 -82
  258. snowflake/ml/registry/_schema_upgrade_plans.py +0 -116
  259. snowflake/ml/registry/_schema_version_manager.py +0 -163
  260. snowflake/ml/registry/model_registry.py +0 -2048
  261. {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.4.dist-info}/LICENSE.txt +0 -0
  262. {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.4.dist-info}/top_level.txt +0 -0
@@ -2,43 +2,49 @@ import dataclasses
2
2
  import hashlib
3
3
  import logging
4
4
  import pathlib
5
- import queue
6
- import sys
5
+ import re
7
6
  import tempfile
8
7
  import threading
9
8
  import time
10
- import uuid
11
9
  from typing import Any, Dict, List, Optional, Tuple, cast
12
10
 
11
+ from packaging import version
12
+
13
13
  from snowflake import snowpark
14
14
  from snowflake.ml._internal import file_utils
15
- from snowflake.ml._internal.utils import sql_identifier
15
+ from snowflake.ml._internal.utils import service_logger, snowflake_env, sql_identifier
16
16
  from snowflake.ml.model._client.service import model_deployment_spec
17
17
  from snowflake.ml.model._client.sql import service as service_sql, stage as stage_sql
18
18
  from snowflake.snowpark import exceptions, row, session
19
19
  from snowflake.snowpark._internal import utils as snowpark_utils
20
20
 
21
-
22
- def get_logger(logger_name: str) -> logging.Logger:
23
- logger = logging.getLogger(logger_name)
24
- logger.setLevel(logging.INFO)
25
- handler = logging.StreamHandler(sys.stdout)
26
- handler.setLevel(logging.INFO)
27
- handler.setFormatter(logging.Formatter("%(name)s [%(asctime)s] [%(levelname)s] %(message)s"))
28
- logger.addHandler(handler)
29
- return logger
30
-
31
-
32
- logger = get_logger(__name__)
33
- logger.propagate = False
21
+ module_logger = service_logger.get_logger(__name__, service_logger.LogColor.GREY)
22
+ module_logger.propagate = False
34
23
 
35
24
 
36
25
  @dataclasses.dataclass
37
26
  class ServiceLogInfo:
38
- service_name: str
27
+ database_name: Optional[sql_identifier.SqlIdentifier]
28
+ schema_name: Optional[sql_identifier.SqlIdentifier]
29
+ service_name: sql_identifier.SqlIdentifier
39
30
  container_name: str
40
31
  instance_id: str = "0"
41
32
 
33
+ def __post_init__(self) -> None:
34
+ # service name used in logs for display
35
+ self.display_service_name = sql_identifier.get_fully_qualified_name(
36
+ self.database_name, self.schema_name, self.service_name
37
+ )
38
+
39
+
40
+ @dataclasses.dataclass
41
+ class ServiceLogMetadata:
42
+ service_logger: logging.Logger
43
+ service: ServiceLogInfo
44
+ service_status: Optional[service_sql.ServiceStatus]
45
+ is_model_build_service_done: bool
46
+ log_offset: int
47
+
42
48
 
43
49
  class ServiceOperator:
44
50
  """Service operator for container services logic."""
@@ -96,6 +102,7 @@ class ServiceOperator:
96
102
  max_instances: int,
97
103
  gpu_requests: Optional[str],
98
104
  num_workers: Optional[int],
105
+ max_batch_rows: Optional[int],
99
106
  force_rebuild: bool,
100
107
  build_external_access_integration: sql_identifier.SqlIdentifier,
101
108
  statement_params: Optional[Dict[str, Any]] = None,
@@ -129,6 +136,7 @@ class ServiceOperator:
129
136
  max_instances=max_instances,
130
137
  gpu=gpu_requests,
131
138
  num_workers=num_workers,
139
+ max_batch_rows=max_batch_rows,
132
140
  force_rebuild=force_rebuild,
133
141
  external_access_integration=build_external_access_integration,
134
142
  )
@@ -140,15 +148,13 @@ class ServiceOperator:
140
148
  )
141
149
 
142
150
  # check if the inference service is already running
143
- try:
144
- model_inference_service_status, _ = self._service_client.get_service_status(
145
- service_name=service_name,
146
- include_message=False,
147
- statement_params=statement_params,
148
- )
149
- model_inference_service_exists = model_inference_service_status == service_sql.ServiceStatus.READY
150
- except exceptions.SnowparkSQLException:
151
- model_inference_service_exists = False
151
+ model_inference_service_exists = self._check_if_service_exists(
152
+ database_name=service_database_name,
153
+ schema_name=service_schema_name,
154
+ service_name=service_name,
155
+ service_status_list_if_exists=[service_sql.ServiceStatus.READY],
156
+ statement_params=statement_params,
157
+ )
152
158
 
153
159
  # deploy the model service
154
160
  query_id, async_job = self._service_client.deploy_model(
@@ -157,39 +163,55 @@ class ServiceOperator:
157
163
  statement_params=statement_params,
158
164
  )
159
165
 
160
- # stream service logs in a thread
161
- services = [
162
- ServiceLogInfo(service_name=self._get_model_build_service_name(query_id), container_name="model-build"),
163
- ServiceLogInfo(service_name=service_name, container_name="model-inference"),
164
- ]
165
- exception_queue: queue.Queue = queue.Queue() # type: ignore[type-arg]
166
- log_thread = self._start_service_log_streaming(
167
- async_job, services, model_inference_service_exists, exception_queue, statement_params
168
- )
169
- log_thread.join()
170
-
171
- try:
172
- # non-blocking check for an exception
173
- exception = exception_queue.get(block=False)
174
- if exception:
175
- raise exception
176
- except queue.Empty:
177
- pass
166
+ # TODO(hayu): Remove the version check after Snowflake 8.37.0 release
167
+ if snowflake_env.get_current_snowflake_version(
168
+ self._session, statement_params=statement_params
169
+ ) >= version.parse("8.37.0"):
170
+ # stream service logs in a thread
171
+ model_build_service_name = sql_identifier.SqlIdentifier(self._get_model_build_service_name(query_id))
172
+ model_build_service = ServiceLogInfo(
173
+ database_name=service_database_name,
174
+ schema_name=service_schema_name,
175
+ service_name=model_build_service_name,
176
+ container_name="model-build",
177
+ )
178
+ model_inference_service = ServiceLogInfo(
179
+ database_name=service_database_name,
180
+ schema_name=service_schema_name,
181
+ service_name=service_name,
182
+ container_name="model-inference",
183
+ )
184
+ services = [model_build_service, model_inference_service]
185
+ log_thread = self._start_service_log_streaming(
186
+ async_job, services, model_inference_service_exists, force_rebuild, statement_params
187
+ )
188
+ log_thread.join()
189
+ else:
190
+ while not async_job.is_done():
191
+ time.sleep(5)
178
192
 
179
- return service_name
193
+ res = cast(str, cast(List[row.Row], async_job.result())[0][0])
194
+ module_logger.info(f"Inference service {service_name} deployment complete: {res}")
195
+ return res
180
196
 
181
197
  def _start_service_log_streaming(
182
198
  self,
183
199
  async_job: snowpark.AsyncJob,
184
200
  services: List[ServiceLogInfo],
185
201
  model_inference_service_exists: bool,
186
- exception_queue: queue.Queue, # type: ignore[type-arg]
202
+ force_rebuild: bool,
187
203
  statement_params: Optional[Dict[str, Any]] = None,
188
204
  ) -> threading.Thread:
189
205
  """Start the service log streaming in a separate thread."""
190
206
  log_thread = threading.Thread(
191
207
  target=self._stream_service_logs,
192
- args=(async_job, services, model_inference_service_exists, exception_queue, statement_params),
208
+ args=(
209
+ async_job,
210
+ services,
211
+ model_inference_service_exists,
212
+ force_rebuild,
213
+ statement_params,
214
+ ),
193
215
  )
194
216
  log_thread.start()
195
217
  return log_thread
@@ -199,15 +221,17 @@ class ServiceOperator:
199
221
  async_job: snowpark.AsyncJob,
200
222
  services: List[ServiceLogInfo],
201
223
  model_inference_service_exists: bool,
202
- exception_queue: queue.Queue, # type: ignore[type-arg]
224
+ force_rebuild: bool,
203
225
  statement_params: Optional[Dict[str, Any]] = None,
204
226
  ) -> None:
205
227
  """Stream service logs while the async job is running."""
206
228
 
207
- def fetch_logs(service_name: str, container_name: str, offset: int) -> Tuple[str, int]:
229
+ def fetch_logs(service: ServiceLogInfo, offset: int) -> Tuple[str, int]:
208
230
  service_logs = self._service_client.get_service_logs(
209
- service_name=service_name,
210
- container_name=container_name,
231
+ database_name=service.database_name,
232
+ schema_name=service.schema_name,
233
+ service_name=service.service_name,
234
+ container_name=service.container_name,
211
235
  statement_params=statement_params,
212
236
  )
213
237
 
@@ -221,67 +245,121 @@ class ServiceOperator:
221
245
 
222
246
  return new_logs, new_offset
223
247
 
224
- is_model_build_service_done = False
225
- log_offset = 0
248
+ def set_service_log_metadata_to_model_inference(
249
+ meta: ServiceLogMetadata, inference_service: ServiceLogInfo, msg: str
250
+ ) -> None:
251
+ model_inference_service_logger = service_logger.get_logger( # InferenceServiceName-InstanceId
252
+ f"{inference_service.display_service_name}-{inference_service.instance_id}",
253
+ service_logger.LogColor.BLUE,
254
+ )
255
+ model_inference_service_logger.propagate = False
256
+ meta.service_logger = model_inference_service_logger
257
+ meta.service = inference_service
258
+ meta.service_status = None
259
+ meta.is_model_build_service_done = True
260
+ meta.log_offset = 0
261
+ block_size = 180
262
+ module_logger.info(msg)
263
+ module_logger.info("-" * block_size)
264
+
226
265
  model_build_service, model_inference_service = services[0], services[1]
227
- service_name, container_name = model_build_service.service_name, model_build_service.container_name
228
- # BuildJobName
229
- service_logger = get_logger(service_name)
230
- service_logger.propagate = False
266
+ model_build_service_logger = service_logger.get_logger( # BuildJobName
267
+ model_build_service.display_service_name, service_logger.LogColor.GREEN
268
+ )
269
+ model_build_service_logger.propagate = False
270
+ service_log_meta = ServiceLogMetadata(
271
+ service_logger=model_build_service_logger,
272
+ service=model_build_service,
273
+ service_status=None,
274
+ is_model_build_service_done=False,
275
+ log_offset=0,
276
+ )
231
277
  while not async_job.is_done():
232
278
  if model_inference_service_exists:
233
279
  time.sleep(5)
234
280
  continue
235
281
 
236
282
  try:
237
- block_size = 180
283
+ # check if using an existing model build image
284
+ if not force_rebuild and not service_log_meta.is_model_build_service_done:
285
+ model_build_service_exists = self._check_if_service_exists(
286
+ database_name=model_build_service.database_name,
287
+ schema_name=model_build_service.schema_name,
288
+ service_name=model_build_service.service_name,
289
+ statement_params=statement_params,
290
+ )
291
+ new_model_inference_service_exists = self._check_if_service_exists(
292
+ database_name=model_inference_service.database_name,
293
+ schema_name=model_inference_service.schema_name,
294
+ service_name=model_inference_service.service_name,
295
+ statement_params=statement_params,
296
+ )
297
+ if not model_build_service_exists and new_model_inference_service_exists:
298
+ set_service_log_metadata_to_model_inference(
299
+ service_log_meta,
300
+ model_inference_service,
301
+ "Model Inference image build is not rebuilding the image and using previously built image.",
302
+ )
303
+ continue
304
+
238
305
  service_status, message = self._service_client.get_service_status(
239
- service_name=service_name, include_message=True, statement_params=statement_params
306
+ database_name=service_log_meta.service.database_name,
307
+ schema_name=service_log_meta.service.schema_name,
308
+ service_name=service_log_meta.service.service_name,
309
+ include_message=True,
310
+ statement_params=statement_params,
240
311
  )
241
- logger.info(f"Inference service {service_name} is {service_status.value}.")
312
+ if (service_status != service_sql.ServiceStatus.READY) or (
313
+ service_status != service_log_meta.service_status
314
+ ):
315
+ service_log_meta.service_status = service_status
316
+ module_logger.info(
317
+ f"{'Inference' if service_log_meta.is_model_build_service_done else 'Image build'} service "
318
+ f"{service_log_meta.service.display_service_name} is "
319
+ f"{service_log_meta.service_status.value}."
320
+ )
321
+ module_logger.info(f"Service message: {message}")
242
322
 
243
- new_logs, new_offset = fetch_logs(service_name, container_name, log_offset)
323
+ new_logs, new_offset = fetch_logs(
324
+ service_log_meta.service,
325
+ service_log_meta.log_offset,
326
+ )
244
327
  if new_logs:
245
- service_logger.info(new_logs)
246
- log_offset = new_offset
328
+ service_log_meta.service_logger.info(new_logs)
329
+ service_log_meta.log_offset = new_offset
247
330
 
248
331
  # check if model build service is done
249
- if not is_model_build_service_done:
332
+ if not service_log_meta.is_model_build_service_done:
250
333
  service_status, _ = self._service_client.get_service_status(
334
+ database_name=model_build_service.database_name,
335
+ schema_name=model_build_service.schema_name,
251
336
  service_name=model_build_service.service_name,
252
337
  include_message=False,
253
338
  statement_params=statement_params,
254
339
  )
255
340
 
256
341
  if service_status == service_sql.ServiceStatus.DONE:
257
- is_model_build_service_done = True
258
- log_offset = 0
259
- service_name = model_inference_service.service_name
260
- container_name = model_inference_service.container_name
261
- # InferenceServiceName-InstanceId
262
- service_logger = get_logger(f"{service_name}-{model_inference_service.instance_id}")
263
- service_logger.propagate = False
264
- logger.info(f"Model build service {model_build_service.service_name} complete.")
265
- logger.info("-" * block_size)
266
- except ValueError:
267
- logger.warning(f"Unknown service status: {service_status.value}")
342
+ set_service_log_metadata_to_model_inference(
343
+ service_log_meta,
344
+ model_inference_service,
345
+ f"Image build service {model_build_service.display_service_name} complete.",
346
+ )
268
347
  except Exception as ex:
269
- logger.warning(f"Caught an exception when logging: {repr(ex)}")
348
+ pattern = r"002003 \(02000\)" # error code: service does not exist
349
+ is_snowpark_sql_exception = isinstance(ex, exceptions.SnowparkSQLException)
350
+ contains_msg = any(msg in str(ex) for msg in ["Pending scheduling", "Waiting to start"])
351
+ matches_pattern = service_log_meta.service_status is None and re.search(pattern, str(ex)) is not None
352
+ if not (is_snowpark_sql_exception and (contains_msg or matches_pattern)):
353
+ module_logger.warning(f"Caught an exception when logging: {repr(ex)}")
270
354
 
271
355
  time.sleep(5)
272
356
 
273
357
  if model_inference_service_exists:
274
- logger.info(f"Inference service {model_inference_service.service_name} is already RUNNING.")
358
+ module_logger.info(f"Inference service {model_inference_service.display_service_name} is already RUNNING.")
275
359
  else:
276
- self._finalize_logs(service_logger, services[-1], log_offset, statement_params)
277
-
278
- # catch exceptions from the deploy model execution
279
- try:
280
- res = cast(List[row.Row], async_job.result())
281
- logger.info(f"Model deployment for inference service {model_inference_service.service_name} complete.")
282
- logger.info(res[0][0])
283
- except Exception as ex:
284
- exception_queue.put(ex)
360
+ self._finalize_logs(
361
+ service_log_meta.service_logger, service_log_meta.service, service_log_meta.log_offset, statement_params
362
+ )
285
363
 
286
364
  def _finalize_logs(
287
365
  self,
@@ -292,7 +370,10 @@ class ServiceOperator:
292
370
  ) -> None:
293
371
  """Fetch service logs after the async job is done to ensure no logs are missed."""
294
372
  try:
373
+ time.sleep(5) # wait for complete service logs
295
374
  service_logs = self._service_client.get_service_logs(
375
+ database_name=service.database_name,
376
+ schema_name=service.schema_name,
296
377
  service_name=service.service_name,
297
378
  container_name=service.container_name,
298
379
  statement_params=statement_params,
@@ -301,12 +382,40 @@ class ServiceOperator:
301
382
  if len(service_logs) > offset:
302
383
  service_logger.info(service_logs[offset:])
303
384
  except Exception as ex:
304
- logger.warning(f"Caught an exception when logging: {repr(ex)}")
385
+ module_logger.warning(f"Caught an exception when logging: {repr(ex)}")
305
386
 
306
387
  @staticmethod
307
388
  def _get_model_build_service_name(query_id: str) -> str:
308
389
  """Get the model build service name through the server-side logic."""
309
- most_significant_bits = uuid.UUID(query_id).int >> 64
310
- md5_hash = hashlib.md5(str(most_significant_bits).encode()).hexdigest()
311
- identifier = md5_hash[:6]
390
+ uuid = query_id.replace("-", "")
391
+ big_int = int(uuid, 16)
392
+ md5_hash = hashlib.md5(str(big_int).encode()).hexdigest()
393
+ identifier = md5_hash[:8]
312
394
  return ("model_build_" + identifier).upper()
395
+
396
+ def _check_if_service_exists(
397
+ self,
398
+ database_name: Optional[sql_identifier.SqlIdentifier],
399
+ schema_name: Optional[sql_identifier.SqlIdentifier],
400
+ service_name: sql_identifier.SqlIdentifier,
401
+ service_status_list_if_exists: Optional[List[service_sql.ServiceStatus]] = None,
402
+ statement_params: Optional[Dict[str, Any]] = None,
403
+ ) -> bool:
404
+ if service_status_list_if_exists is None:
405
+ service_status_list_if_exists = [
406
+ service_sql.ServiceStatus.PENDING,
407
+ service_sql.ServiceStatus.READY,
408
+ service_sql.ServiceStatus.DONE,
409
+ service_sql.ServiceStatus.FAILED,
410
+ ]
411
+ try:
412
+ service_status, _ = self._service_client.get_service_status(
413
+ database_name=database_name,
414
+ schema_name=schema_name,
415
+ service_name=service_name,
416
+ include_message=False,
417
+ statement_params=statement_params,
418
+ )
419
+ return any(service_status == status for status in service_status_list_if_exists)
420
+ except exceptions.SnowparkSQLException:
421
+ return False
@@ -38,6 +38,7 @@ class ModelDeploymentSpec:
38
38
  max_instances: int,
39
39
  gpu: Optional[str],
40
40
  num_workers: Optional[int],
41
+ max_batch_rows: Optional[int],
41
42
  force_rebuild: bool,
42
43
  external_access_integration: sql_identifier.SqlIdentifier,
43
44
  ) -> None:
@@ -79,6 +80,9 @@ class ModelDeploymentSpec:
79
80
  if num_workers:
80
81
  service_dict["num_workers"] = num_workers
81
82
 
83
+ if max_batch_rows:
84
+ service_dict["max_batch_rows"] = max_batch_rows
85
+
82
86
  # model deployment spec
83
87
  model_deployment_spec_dict = model_deployment_spec_schema.ModelDeploymentSpecDict(
84
88
  models=[model_dict],
@@ -22,6 +22,7 @@ class ServiceDict(TypedDict):
22
22
  max_instances: Required[int]
23
23
  gpu: NotRequired[str]
24
24
  num_workers: NotRequired[int]
25
+ max_batch_rows: NotRequired[int]
25
26
 
26
27
 
27
28
  class ModelDeploymentSpecDict(TypedDict):
@@ -2,6 +2,7 @@ from typing import Optional
2
2
 
3
3
  from snowflake.ml._internal.utils import identifier, sql_identifier
4
4
  from snowflake.snowpark import session
5
+ from snowflake.snowpark._internal import utils as snowpark_utils
5
6
 
6
7
 
7
8
  class _BaseSQLClient:
@@ -32,3 +33,7 @@ class _BaseSQLClient:
32
33
  return identifier.get_schema_level_object_identifier(
33
34
  actual_database_name.identifier(), actual_schema_name.identifier(), object_name.identifier()
34
35
  )
36
+
37
+ @staticmethod
38
+ def get_tmp_name_with_prefix(prefix: str) -> str:
39
+ return f"{prefix}_{snowpark_utils.generate_random_alphanumeric().upper()}"
@@ -15,6 +15,7 @@ class ModelSQLClient(_base._BaseSQLClient):
15
15
  MODEL_VERSION_METADATA_COL_NAME = "metadata"
16
16
  MODEL_VERSION_MODEL_SPEC_COL_NAME = "model_spec"
17
17
  MODEL_VERSION_ALIASES_COL_NAME = "aliases"
18
+ MODEL_VERSION_INFERENCE_SERVICES_COL_NAME = "inference_services"
18
19
 
19
20
  def show_models(
20
21
  self,
@@ -298,7 +298,9 @@ class ModelVersionSQLClient(_base._BaseSQLClient):
298
298
  ) -> dataframe.DataFrame:
299
299
  with_statements = []
300
300
  if len(input_df.queries["queries"]) == 1 and len(input_df.queries["post_actions"]) == 0:
301
- INTERMEDIATE_TABLE_NAME = "SNOWPARK_ML_MODEL_INFERENCE_INPUT"
301
+ INTERMEDIATE_TABLE_NAME = ModelVersionSQLClient.get_tmp_name_with_prefix(
302
+ "SNOWPARK_ML_MODEL_INFERENCE_INPUT"
303
+ )
302
304
  with_statements.append(f"{INTERMEDIATE_TABLE_NAME} AS ({input_df.queries['queries'][0]})")
303
305
  else:
304
306
  actual_database_name = database_name or self._database_name
@@ -316,9 +318,9 @@ class ModelVersionSQLClient(_base._BaseSQLClient):
316
318
  statement_params=statement_params,
317
319
  )
318
320
 
319
- INTERMEDIATE_OBJ_NAME = "TMP_RESULT"
321
+ INTERMEDIATE_OBJ_NAME = ModelVersionSQLClient.get_tmp_name_with_prefix("TMP_RESULT")
320
322
 
321
- module_version_alias = "MODEL_VERSION_ALIAS"
323
+ module_version_alias = ModelVersionSQLClient.get_tmp_name_with_prefix("MODEL_VERSION_ALIAS")
322
324
  with_statements.append(
323
325
  f"{module_version_alias} AS "
324
326
  f"MODEL {self.fully_qualified_object_name(database_name, schema_name, model_name)}"
@@ -375,7 +377,9 @@ class ModelVersionSQLClient(_base._BaseSQLClient):
375
377
  ) -> dataframe.DataFrame:
376
378
  with_statements = []
377
379
  if len(input_df.queries["queries"]) == 1 and len(input_df.queries["post_actions"]) == 0:
378
- INTERMEDIATE_TABLE_NAME = "SNOWPARK_ML_MODEL_INFERENCE_INPUT"
380
+ INTERMEDIATE_TABLE_NAME = (
381
+ f"SNOWPARK_ML_MODEL_INFERENCE_INPUT_{snowpark_utils.generate_random_alphanumeric().upper()}"
382
+ )
379
383
  with_statements.append(f"{INTERMEDIATE_TABLE_NAME} AS ({input_df.queries['queries'][0]})")
380
384
  else:
381
385
  actual_database_name = database_name or self._database_name
@@ -393,7 +397,7 @@ class ModelVersionSQLClient(_base._BaseSQLClient):
393
397
  statement_params=statement_params,
394
398
  )
395
399
 
396
- module_version_alias = "MODEL_VERSION_ALIAS"
400
+ module_version_alias = f"MODEL_VERSION_ALIAS_{snowpark_utils.generate_random_alphanumeric().upper()}"
397
401
  with_statements.append(
398
402
  f"{module_version_alias} AS "
399
403
  f"MODEL {self.fully_qualified_object_name(database_name, schema_name, model_name)}"
@@ -92,15 +92,8 @@ class ServiceSQLClient(_base._BaseSQLClient):
92
92
  actual_database_name = database_name or self._database_name
93
93
  actual_schema_name = schema_name or self._schema_name
94
94
 
95
- function_name = identifier.concat_names([service_name.identifier(), "_", method_name.identifier()])
96
- fully_qualified_function_name = identifier.get_schema_level_object_identifier(
97
- actual_database_name.identifier(),
98
- actual_schema_name.identifier(),
99
- function_name,
100
- )
101
-
102
95
  if len(input_df.queries["queries"]) == 1 and len(input_df.queries["post_actions"]) == 0:
103
- INTERMEDIATE_TABLE_NAME = "SNOWPARK_ML_MODEL_INFERENCE_INPUT"
96
+ INTERMEDIATE_TABLE_NAME = ServiceSQLClient.get_tmp_name_with_prefix("SNOWPARK_ML_MODEL_INFERENCE_INPUT")
104
97
  with_statements.append(f"{INTERMEDIATE_TABLE_NAME} AS ({input_df.queries['queries'][0]})")
105
98
  else:
106
99
  tmp_table_name = snowpark_utils.random_name_for_temp_object(snowpark_utils.TempObjectType.TABLE)
@@ -116,7 +109,7 @@ class ServiceSQLClient(_base._BaseSQLClient):
116
109
  statement_params=statement_params,
117
110
  )
118
111
 
119
- INTERMEDIATE_OBJ_NAME = "TMP_RESULT"
112
+ INTERMEDIATE_OBJ_NAME = ServiceSQLClient.get_tmp_name_with_prefix("TMP_RESULT")
120
113
 
121
114
  with_sql = f"WITH {','.join(with_statements)}" if with_statements else ""
122
115
  args_sql_list = []
@@ -124,6 +117,13 @@ class ServiceSQLClient(_base._BaseSQLClient):
124
117
  args_sql_list.append(input_arg_value)
125
118
  args_sql = ", ".join(args_sql_list)
126
119
 
120
+ function_name = identifier.concat_names([service_name.identifier(), "_", method_name.identifier()])
121
+ fully_qualified_function_name = identifier.get_schema_level_object_identifier(
122
+ actual_database_name.identifier(),
123
+ actual_schema_name.identifier(),
124
+ function_name,
125
+ )
126
+
127
127
  sql = textwrap.dedent(
128
128
  f"""{with_sql}
129
129
  SELECT *,
@@ -154,7 +154,9 @@ class ServiceSQLClient(_base._BaseSQLClient):
154
154
  def get_service_logs(
155
155
  self,
156
156
  *,
157
- service_name: str,
157
+ database_name: Optional[sql_identifier.SqlIdentifier],
158
+ schema_name: Optional[sql_identifier.SqlIdentifier],
159
+ service_name: sql_identifier.SqlIdentifier,
158
160
  instance_id: str = "0",
159
161
  container_name: str,
160
162
  statement_params: Optional[Dict[str, Any]] = None,
@@ -163,7 +165,11 @@ class ServiceSQLClient(_base._BaseSQLClient):
163
165
  rows = (
164
166
  query_result_checker.SqlResultValidator(
165
167
  self._session,
166
- f"CALL {system_func}('{service_name}', '{instance_id}', '{container_name}')",
168
+ (
169
+ f"CALL {system_func}("
170
+ f"'{self.fully_qualified_object_name(database_name, schema_name, service_name)}', '{instance_id}', "
171
+ f"'{container_name}')"
172
+ ),
167
173
  statement_params=statement_params,
168
174
  )
169
175
  .has_dimensions(expected_rows=1, expected_cols=1)
@@ -174,7 +180,9 @@ class ServiceSQLClient(_base._BaseSQLClient):
174
180
  def get_service_status(
175
181
  self,
176
182
  *,
177
- service_name: str,
183
+ database_name: Optional[sql_identifier.SqlIdentifier],
184
+ schema_name: Optional[sql_identifier.SqlIdentifier],
185
+ service_name: sql_identifier.SqlIdentifier,
178
186
  include_message: bool = False,
179
187
  statement_params: Optional[Dict[str, Any]] = None,
180
188
  ) -> Tuple[ServiceStatus, Optional[str]]:
@@ -182,7 +190,7 @@ class ServiceSQLClient(_base._BaseSQLClient):
182
190
  rows = (
183
191
  query_result_checker.SqlResultValidator(
184
192
  self._session,
185
- f"CALL {system_func}('{service_name}')",
193
+ f"CALL {system_func}('{self.fully_qualified_object_name(database_name, schema_name, service_name)}')",
186
194
  statement_params=statement_params,
187
195
  )
188
196
  .has_dimensions(expected_rows=1, expected_cols=1)
@@ -194,3 +202,17 @@ class ServiceSQLClient(_base._BaseSQLClient):
194
202
  message = metadata["message"] if include_message else None
195
203
  return service_status, message
196
204
  return ServiceStatus.UNKNOWN, None
205
+
206
+ def drop_service(
207
+ self,
208
+ *,
209
+ database_name: Optional[sql_identifier.SqlIdentifier],
210
+ schema_name: Optional[sql_identifier.SqlIdentifier],
211
+ service_name: sql_identifier.SqlIdentifier,
212
+ statement_params: Optional[Dict[str, Any]] = None,
213
+ ) -> None:
214
+ query_result_checker.SqlResultValidator(
215
+ self._session,
216
+ f"DROP SERVICE {self.fully_qualified_object_name(database_name, schema_name, service_name)}",
217
+ statement_params=statement_params,
218
+ ).has_dimensions(expected_rows=1, expected_cols=1).validate()