snowflake-ml-python 1.6.2__py3-none-any.whl → 1.6.3__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.
- snowflake/cortex/__init__.py +4 -0
- snowflake/cortex/_classify_text.py +2 -2
- snowflake/cortex/_embed_text_1024.py +37 -0
- snowflake/cortex/_embed_text_768.py +37 -0
- snowflake/cortex/_extract_answer.py +2 -2
- snowflake/cortex/_sentiment.py +2 -2
- snowflake/cortex/_summarize.py +2 -2
- snowflake/cortex/_translate.py +2 -2
- snowflake/cortex/_util.py +4 -4
- snowflake/ml/_internal/env_utils.py +5 -5
- snowflake/ml/_internal/exceptions/error_codes.py +2 -0
- snowflake/ml/_internal/utils/db_utils.py +50 -0
- snowflake/ml/_internal/utils/service_logger.py +63 -0
- snowflake/ml/_internal/utils/sql_identifier.py +25 -1
- snowflake/ml/data/_internal/arrow_ingestor.py +1 -11
- snowflake/ml/data/ingestor_utils.py +20 -10
- snowflake/ml/feature_store/access_manager.py +3 -3
- snowflake/ml/feature_store/feature_store.py +19 -2
- snowflake/ml/feature_store/feature_view.py +82 -28
- snowflake/ml/fileset/stage_fs.py +2 -1
- snowflake/ml/lineage/lineage_node.py +7 -2
- snowflake/ml/model/__init__.py +1 -2
- snowflake/ml/model/_client/model/model_version_impl.py +78 -9
- snowflake/ml/model/_client/ops/model_ops.py +89 -7
- snowflake/ml/model/_client/ops/service_ops.py +200 -91
- snowflake/ml/model/_client/service/model_deployment_spec.py +4 -0
- snowflake/ml/model/_client/service/model_deployment_spec_schema.py +1 -0
- snowflake/ml/model/_client/sql/_base.py +5 -0
- snowflake/ml/model/_client/sql/model.py +1 -0
- snowflake/ml/model/_client/sql/model_version.py +9 -5
- snowflake/ml/model/_client/sql/service.py +47 -13
- snowflake/ml/model/_model_composer/model_composer.py +11 -41
- snowflake/ml/model/_model_composer/model_manifest/model_manifest.py +29 -4
- snowflake/ml/model/_packager/model_env/model_env.py +4 -38
- snowflake/ml/model/_packager/model_handlers/_utils.py +106 -32
- snowflake/ml/model/_packager/model_handlers/catboost.py +26 -27
- snowflake/ml/model/_packager/model_handlers/huggingface_pipeline.py +3 -3
- snowflake/ml/model/_packager/model_handlers/lightgbm.py +21 -6
- snowflake/ml/model/_packager/model_handlers/mlflow.py +3 -5
- snowflake/ml/model/_packager/model_handlers/model_objective_utils.py +111 -58
- snowflake/ml/model/_packager/model_handlers/sentence_transformers.py +15 -8
- snowflake/ml/model/_packager/model_handlers/sklearn.py +50 -66
- snowflake/ml/model/_packager/model_handlers/snowmlmodel.py +36 -17
- snowflake/ml/model/_packager/model_handlers/xgboost.py +22 -7
- snowflake/ml/model/_packager/model_meta/model_meta.py +16 -45
- snowflake/ml/model/_packager/model_meta/model_meta_schema.py +1 -6
- snowflake/ml/model/_packager/model_packager.py +14 -10
- snowflake/ml/model/_packager/model_runtime/model_runtime.py +11 -0
- snowflake/ml/model/_signatures/snowpark_handler.py +3 -2
- snowflake/ml/model/type_hints.py +11 -152
- snowflake/ml/modeling/_internal/snowpark_implementations/distributed_hpo_trainer.py +0 -2
- snowflake/ml/modeling/_internal/snowpark_implementations/snowpark_trainer.py +17 -6
- snowflake/ml/modeling/_internal/snowpark_implementations/xgboost_external_memory_trainer.py +0 -1
- snowflake/ml/modeling/calibration/calibrated_classifier_cv.py +1 -0
- snowflake/ml/modeling/cluster/affinity_propagation.py +1 -0
- snowflake/ml/modeling/cluster/agglomerative_clustering.py +1 -0
- snowflake/ml/modeling/cluster/birch.py +1 -0
- snowflake/ml/modeling/cluster/bisecting_k_means.py +1 -0
- snowflake/ml/modeling/cluster/dbscan.py +1 -0
- snowflake/ml/modeling/cluster/feature_agglomeration.py +1 -0
- snowflake/ml/modeling/cluster/k_means.py +1 -0
- snowflake/ml/modeling/cluster/mean_shift.py +1 -0
- snowflake/ml/modeling/cluster/mini_batch_k_means.py +1 -0
- snowflake/ml/modeling/cluster/optics.py +1 -0
- snowflake/ml/modeling/cluster/spectral_biclustering.py +1 -0
- snowflake/ml/modeling/cluster/spectral_clustering.py +1 -0
- snowflake/ml/modeling/cluster/spectral_coclustering.py +1 -0
- snowflake/ml/modeling/compose/column_transformer.py +1 -0
- snowflake/ml/modeling/compose/transformed_target_regressor.py +1 -0
- snowflake/ml/modeling/covariance/elliptic_envelope.py +1 -0
- snowflake/ml/modeling/covariance/empirical_covariance.py +1 -0
- snowflake/ml/modeling/covariance/graphical_lasso.py +1 -0
- snowflake/ml/modeling/covariance/graphical_lasso_cv.py +1 -0
- snowflake/ml/modeling/covariance/ledoit_wolf.py +1 -0
- snowflake/ml/modeling/covariance/min_cov_det.py +1 -0
- snowflake/ml/modeling/covariance/oas.py +1 -0
- snowflake/ml/modeling/covariance/shrunk_covariance.py +1 -0
- snowflake/ml/modeling/decomposition/dictionary_learning.py +1 -0
- snowflake/ml/modeling/decomposition/factor_analysis.py +1 -0
- snowflake/ml/modeling/decomposition/fast_ica.py +1 -0
- snowflake/ml/modeling/decomposition/incremental_pca.py +1 -0
- snowflake/ml/modeling/decomposition/kernel_pca.py +1 -0
- snowflake/ml/modeling/decomposition/mini_batch_dictionary_learning.py +1 -0
- snowflake/ml/modeling/decomposition/mini_batch_sparse_pca.py +1 -0
- snowflake/ml/modeling/decomposition/pca.py +1 -0
- snowflake/ml/modeling/decomposition/sparse_pca.py +1 -0
- snowflake/ml/modeling/decomposition/truncated_svd.py +1 -0
- snowflake/ml/modeling/discriminant_analysis/linear_discriminant_analysis.py +1 -0
- snowflake/ml/modeling/discriminant_analysis/quadratic_discriminant_analysis.py +1 -0
- snowflake/ml/modeling/ensemble/ada_boost_classifier.py +1 -0
- snowflake/ml/modeling/ensemble/ada_boost_regressor.py +1 -0
- snowflake/ml/modeling/ensemble/bagging_classifier.py +1 -0
- snowflake/ml/modeling/ensemble/bagging_regressor.py +1 -0
- snowflake/ml/modeling/ensemble/extra_trees_classifier.py +1 -0
- snowflake/ml/modeling/ensemble/extra_trees_regressor.py +1 -0
- snowflake/ml/modeling/ensemble/gradient_boosting_classifier.py +1 -0
- snowflake/ml/modeling/ensemble/gradient_boosting_regressor.py +1 -0
- snowflake/ml/modeling/ensemble/hist_gradient_boosting_classifier.py +1 -0
- snowflake/ml/modeling/ensemble/hist_gradient_boosting_regressor.py +1 -0
- snowflake/ml/modeling/ensemble/isolation_forest.py +1 -0
- snowflake/ml/modeling/ensemble/random_forest_classifier.py +1 -0
- snowflake/ml/modeling/ensemble/random_forest_regressor.py +1 -0
- snowflake/ml/modeling/ensemble/stacking_regressor.py +1 -0
- snowflake/ml/modeling/ensemble/voting_classifier.py +1 -0
- snowflake/ml/modeling/ensemble/voting_regressor.py +1 -0
- snowflake/ml/modeling/feature_selection/generic_univariate_select.py +1 -0
- snowflake/ml/modeling/feature_selection/select_fdr.py +1 -0
- snowflake/ml/modeling/feature_selection/select_fpr.py +1 -0
- snowflake/ml/modeling/feature_selection/select_fwe.py +1 -0
- snowflake/ml/modeling/feature_selection/select_k_best.py +1 -0
- snowflake/ml/modeling/feature_selection/select_percentile.py +1 -0
- snowflake/ml/modeling/feature_selection/sequential_feature_selector.py +1 -0
- snowflake/ml/modeling/feature_selection/variance_threshold.py +1 -0
- snowflake/ml/modeling/gaussian_process/gaussian_process_classifier.py +1 -0
- snowflake/ml/modeling/gaussian_process/gaussian_process_regressor.py +1 -0
- snowflake/ml/modeling/impute/iterative_imputer.py +1 -0
- snowflake/ml/modeling/impute/knn_imputer.py +1 -0
- snowflake/ml/modeling/impute/missing_indicator.py +1 -0
- snowflake/ml/modeling/kernel_approximation/additive_chi2_sampler.py +1 -0
- snowflake/ml/modeling/kernel_approximation/nystroem.py +1 -0
- snowflake/ml/modeling/kernel_approximation/polynomial_count_sketch.py +1 -0
- snowflake/ml/modeling/kernel_approximation/rbf_sampler.py +1 -0
- snowflake/ml/modeling/kernel_approximation/skewed_chi2_sampler.py +1 -0
- snowflake/ml/modeling/kernel_ridge/kernel_ridge.py +1 -0
- snowflake/ml/modeling/lightgbm/lgbm_classifier.py +1 -0
- snowflake/ml/modeling/lightgbm/lgbm_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/ard_regression.py +1 -0
- snowflake/ml/modeling/linear_model/bayesian_ridge.py +1 -0
- snowflake/ml/modeling/linear_model/elastic_net.py +1 -0
- snowflake/ml/modeling/linear_model/elastic_net_cv.py +1 -0
- snowflake/ml/modeling/linear_model/gamma_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/huber_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/lars.py +1 -0
- snowflake/ml/modeling/linear_model/lars_cv.py +1 -0
- snowflake/ml/modeling/linear_model/lasso.py +1 -0
- snowflake/ml/modeling/linear_model/lasso_cv.py +1 -0
- snowflake/ml/modeling/linear_model/lasso_lars.py +1 -0
- snowflake/ml/modeling/linear_model/lasso_lars_cv.py +1 -0
- snowflake/ml/modeling/linear_model/lasso_lars_ic.py +1 -0
- snowflake/ml/modeling/linear_model/linear_regression.py +1 -0
- snowflake/ml/modeling/linear_model/logistic_regression.py +1 -0
- snowflake/ml/modeling/linear_model/logistic_regression_cv.py +1 -0
- snowflake/ml/modeling/linear_model/multi_task_elastic_net.py +1 -0
- snowflake/ml/modeling/linear_model/multi_task_elastic_net_cv.py +1 -0
- snowflake/ml/modeling/linear_model/multi_task_lasso.py +1 -0
- snowflake/ml/modeling/linear_model/multi_task_lasso_cv.py +1 -0
- snowflake/ml/modeling/linear_model/orthogonal_matching_pursuit.py +1 -0
- snowflake/ml/modeling/linear_model/passive_aggressive_classifier.py +1 -0
- snowflake/ml/modeling/linear_model/passive_aggressive_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/perceptron.py +1 -0
- snowflake/ml/modeling/linear_model/poisson_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/ransac_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/ridge.py +1 -0
- snowflake/ml/modeling/linear_model/ridge_classifier.py +1 -0
- snowflake/ml/modeling/linear_model/ridge_classifier_cv.py +1 -0
- snowflake/ml/modeling/linear_model/ridge_cv.py +1 -0
- snowflake/ml/modeling/linear_model/sgd_classifier.py +1 -0
- snowflake/ml/modeling/linear_model/sgd_one_class_svm.py +1 -0
- snowflake/ml/modeling/linear_model/sgd_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/theil_sen_regressor.py +1 -0
- snowflake/ml/modeling/linear_model/tweedie_regressor.py +1 -0
- snowflake/ml/modeling/manifold/isomap.py +1 -0
- snowflake/ml/modeling/manifold/mds.py +1 -0
- snowflake/ml/modeling/manifold/spectral_embedding.py +1 -0
- snowflake/ml/modeling/manifold/tsne.py +1 -0
- snowflake/ml/modeling/metrics/metrics_utils.py +2 -2
- snowflake/ml/modeling/metrics/ranking.py +0 -3
- snowflake/ml/modeling/metrics/regression.py +0 -3
- snowflake/ml/modeling/mixture/bayesian_gaussian_mixture.py +1 -0
- snowflake/ml/modeling/mixture/gaussian_mixture.py +1 -0
- snowflake/ml/modeling/multiclass/one_vs_one_classifier.py +1 -0
- snowflake/ml/modeling/multiclass/one_vs_rest_classifier.py +1 -0
- snowflake/ml/modeling/multiclass/output_code_classifier.py +1 -0
- snowflake/ml/modeling/naive_bayes/bernoulli_nb.py +1 -0
- snowflake/ml/modeling/naive_bayes/categorical_nb.py +1 -0
- snowflake/ml/modeling/naive_bayes/complement_nb.py +1 -0
- snowflake/ml/modeling/naive_bayes/gaussian_nb.py +1 -0
- snowflake/ml/modeling/naive_bayes/multinomial_nb.py +1 -0
- snowflake/ml/modeling/neighbors/k_neighbors_classifier.py +1 -0
- snowflake/ml/modeling/neighbors/k_neighbors_regressor.py +1 -0
- snowflake/ml/modeling/neighbors/kernel_density.py +1 -0
- snowflake/ml/modeling/neighbors/local_outlier_factor.py +1 -0
- snowflake/ml/modeling/neighbors/nearest_centroid.py +1 -0
- snowflake/ml/modeling/neighbors/nearest_neighbors.py +1 -0
- snowflake/ml/modeling/neighbors/neighborhood_components_analysis.py +1 -0
- snowflake/ml/modeling/neighbors/radius_neighbors_classifier.py +1 -0
- snowflake/ml/modeling/neighbors/radius_neighbors_regressor.py +1 -0
- snowflake/ml/modeling/neural_network/bernoulli_rbm.py +1 -0
- snowflake/ml/modeling/neural_network/mlp_classifier.py +1 -0
- snowflake/ml/modeling/neural_network/mlp_regressor.py +1 -0
- snowflake/ml/modeling/pipeline/pipeline.py +0 -1
- snowflake/ml/modeling/preprocessing/polynomial_features.py +1 -0
- snowflake/ml/modeling/semi_supervised/label_propagation.py +1 -0
- snowflake/ml/modeling/semi_supervised/label_spreading.py +1 -0
- snowflake/ml/modeling/svm/linear_svc.py +1 -0
- snowflake/ml/modeling/svm/linear_svr.py +1 -0
- snowflake/ml/modeling/svm/nu_svc.py +1 -0
- snowflake/ml/modeling/svm/nu_svr.py +1 -0
- snowflake/ml/modeling/svm/svc.py +1 -0
- snowflake/ml/modeling/svm/svr.py +1 -0
- snowflake/ml/modeling/tree/decision_tree_classifier.py +1 -0
- snowflake/ml/modeling/tree/decision_tree_regressor.py +1 -0
- snowflake/ml/modeling/tree/extra_tree_classifier.py +1 -0
- snowflake/ml/modeling/tree/extra_tree_regressor.py +1 -0
- snowflake/ml/modeling/xgboost/xgb_classifier.py +1 -0
- snowflake/ml/modeling/xgboost/xgb_regressor.py +1 -0
- snowflake/ml/modeling/xgboost/xgbrf_classifier.py +1 -0
- snowflake/ml/modeling/xgboost/xgbrf_regressor.py +1 -0
- snowflake/ml/monitoring/_client/model_monitor.py +126 -0
- snowflake/ml/monitoring/_client/model_monitor_manager.py +361 -0
- snowflake/ml/monitoring/_client/model_monitor_version.py +1 -0
- snowflake/ml/monitoring/_client/monitor_sql_client.py +1335 -0
- snowflake/ml/monitoring/_client/queries/record_count.ssql +14 -0
- snowflake/ml/monitoring/_client/queries/rmse.ssql +28 -0
- snowflake/ml/monitoring/entities/model_monitor_config.py +28 -0
- snowflake/ml/monitoring/entities/model_monitor_interval.py +46 -0
- snowflake/ml/monitoring/entities/output_score_type.py +90 -0
- snowflake/ml/registry/_manager/model_manager.py +4 -4
- snowflake/ml/registry/registry.py +165 -6
- snowflake/ml/version.py +1 -1
- {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.3.dist-info}/METADATA +24 -9
- {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.3.dist-info}/RECORD +225 -249
- {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.3.dist-info}/WHEEL +1 -1
- snowflake/ml/_internal/container_services/image_registry/credential.py +0 -84
- snowflake/ml/_internal/container_services/image_registry/http_client.py +0 -127
- snowflake/ml/_internal/container_services/image_registry/imagelib.py +0 -400
- snowflake/ml/_internal/container_services/image_registry/registry_client.py +0 -212
- snowflake/ml/_internal/utils/log_stream_processor.py +0 -30
- snowflake/ml/_internal/utils/session_token_manager.py +0 -46
- snowflake/ml/_internal/utils/spcs_attribution_utils.py +0 -122
- snowflake/ml/_internal/utils/uri.py +0 -77
- snowflake/ml/model/_api.py +0 -568
- snowflake/ml/model/_deploy_client/image_builds/base_image_builder.py +0 -12
- snowflake/ml/model/_deploy_client/image_builds/client_image_builder.py +0 -249
- snowflake/ml/model/_deploy_client/image_builds/docker_context.py +0 -130
- snowflake/ml/model/_deploy_client/image_builds/gunicorn_run.sh +0 -36
- snowflake/ml/model/_deploy_client/image_builds/inference_server/main.py +0 -268
- snowflake/ml/model/_deploy_client/image_builds/server_image_builder.py +0 -215
- snowflake/ml/model/_deploy_client/image_builds/templates/dockerfile_template +0 -53
- snowflake/ml/model/_deploy_client/image_builds/templates/image_build_job_spec_template +0 -38
- snowflake/ml/model/_deploy_client/image_builds/templates/kaniko_shell_script_template +0 -105
- snowflake/ml/model/_deploy_client/snowservice/deploy.py +0 -611
- snowflake/ml/model/_deploy_client/snowservice/deploy_options.py +0 -116
- snowflake/ml/model/_deploy_client/snowservice/instance_types.py +0 -10
- snowflake/ml/model/_deploy_client/snowservice/templates/service_spec_template +0 -28
- snowflake/ml/model/_deploy_client/snowservice/templates/service_spec_template_with_model +0 -21
- snowflake/ml/model/_deploy_client/utils/constants.py +0 -48
- snowflake/ml/model/_deploy_client/utils/snowservice_client.py +0 -280
- snowflake/ml/model/_deploy_client/warehouse/deploy.py +0 -202
- snowflake/ml/model/_deploy_client/warehouse/infer_template.py +0 -99
- snowflake/ml/model/_packager/model_handlers/llm.py +0 -269
- snowflake/ml/model/_packager/model_meta/_core_requirements.py +0 -11
- snowflake/ml/model/deploy_platforms.py +0 -6
- snowflake/ml/model/models/llm.py +0 -106
- snowflake/ml/monitoring/monitor.py +0 -203
- snowflake/ml/registry/_initial_schema.py +0 -142
- snowflake/ml/registry/_schema.py +0 -82
- snowflake/ml/registry/_schema_upgrade_plans.py +0 -116
- snowflake/ml/registry/_schema_version_manager.py +0 -163
- snowflake/ml/registry/model_registry.py +0 -2048
- {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.3.dist-info}/LICENSE.txt +0 -0
- {snowflake_ml_python-1.6.2.dist-info → snowflake_ml_python-1.6.3.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
|
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
|
-
|
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
|
-
|
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
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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
|
-
#
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
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
|
-
|
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
|
-
|
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=(
|
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
|
-
|
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(
|
229
|
+
def fetch_logs(service: ServiceLogInfo, offset: int) -> Tuple[str, int]:
|
208
230
|
service_logs = self._service_client.get_service_logs(
|
209
|
-
|
210
|
-
|
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
|
-
|
225
|
-
|
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
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
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
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
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
|
-
|
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
|
-
|
358
|
+
module_logger.info(f"Inference service {model_inference_service.display_service_name} is already RUNNING.")
|
275
359
|
else:
|
276
|
-
self._finalize_logs(
|
277
|
-
|
278
|
-
|
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
|
-
|
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
|
-
|
310
|
-
|
311
|
-
|
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],
|
@@ -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 =
|
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 =
|
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 = "
|
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)}"
|
@@ -3,10 +3,13 @@ import json
|
|
3
3
|
import textwrap
|
4
4
|
from typing import Any, Dict, List, Optional, Tuple
|
5
5
|
|
6
|
+
from packaging import version
|
7
|
+
|
6
8
|
from snowflake import snowpark
|
7
9
|
from snowflake.ml._internal.utils import (
|
8
10
|
identifier,
|
9
11
|
query_result_checker,
|
12
|
+
snowflake_env,
|
10
13
|
sql_identifier,
|
11
14
|
)
|
12
15
|
from snowflake.ml.model._client.sql import _base
|
@@ -92,15 +95,8 @@ class ServiceSQLClient(_base._BaseSQLClient):
|
|
92
95
|
actual_database_name = database_name or self._database_name
|
93
96
|
actual_schema_name = schema_name or self._schema_name
|
94
97
|
|
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
98
|
if len(input_df.queries["queries"]) == 1 and len(input_df.queries["post_actions"]) == 0:
|
103
|
-
INTERMEDIATE_TABLE_NAME = "SNOWPARK_ML_MODEL_INFERENCE_INPUT"
|
99
|
+
INTERMEDIATE_TABLE_NAME = ServiceSQLClient.get_tmp_name_with_prefix("SNOWPARK_ML_MODEL_INFERENCE_INPUT")
|
104
100
|
with_statements.append(f"{INTERMEDIATE_TABLE_NAME} AS ({input_df.queries['queries'][0]})")
|
105
101
|
else:
|
106
102
|
tmp_table_name = snowpark_utils.random_name_for_temp_object(snowpark_utils.TempObjectType.TABLE)
|
@@ -116,7 +112,7 @@ class ServiceSQLClient(_base._BaseSQLClient):
|
|
116
112
|
statement_params=statement_params,
|
117
113
|
)
|
118
114
|
|
119
|
-
INTERMEDIATE_OBJ_NAME = "TMP_RESULT"
|
115
|
+
INTERMEDIATE_OBJ_NAME = ServiceSQLClient.get_tmp_name_with_prefix("TMP_RESULT")
|
120
116
|
|
121
117
|
with_sql = f"WITH {','.join(with_statements)}" if with_statements else ""
|
122
118
|
args_sql_list = []
|
@@ -124,6 +120,22 @@ class ServiceSQLClient(_base._BaseSQLClient):
|
|
124
120
|
args_sql_list.append(input_arg_value)
|
125
121
|
args_sql = ", ".join(args_sql_list)
|
126
122
|
|
123
|
+
if snowflake_env.get_current_snowflake_version(
|
124
|
+
self._session, statement_params=statement_params
|
125
|
+
) >= version.parse("8.39.0"):
|
126
|
+
fully_qualified_service_name = self.fully_qualified_object_name(
|
127
|
+
actual_database_name, actual_schema_name, service_name
|
128
|
+
)
|
129
|
+
fully_qualified_function_name = f"{fully_qualified_service_name}!{method_name.identifier()}"
|
130
|
+
|
131
|
+
else:
|
132
|
+
function_name = identifier.concat_names([service_name.identifier(), "_", method_name.identifier()])
|
133
|
+
fully_qualified_function_name = identifier.get_schema_level_object_identifier(
|
134
|
+
actual_database_name.identifier(),
|
135
|
+
actual_schema_name.identifier(),
|
136
|
+
function_name,
|
137
|
+
)
|
138
|
+
|
127
139
|
sql = textwrap.dedent(
|
128
140
|
f"""{with_sql}
|
129
141
|
SELECT *,
|
@@ -154,7 +166,9 @@ class ServiceSQLClient(_base._BaseSQLClient):
|
|
154
166
|
def get_service_logs(
|
155
167
|
self,
|
156
168
|
*,
|
157
|
-
|
169
|
+
database_name: Optional[sql_identifier.SqlIdentifier],
|
170
|
+
schema_name: Optional[sql_identifier.SqlIdentifier],
|
171
|
+
service_name: sql_identifier.SqlIdentifier,
|
158
172
|
instance_id: str = "0",
|
159
173
|
container_name: str,
|
160
174
|
statement_params: Optional[Dict[str, Any]] = None,
|
@@ -163,7 +177,11 @@ class ServiceSQLClient(_base._BaseSQLClient):
|
|
163
177
|
rows = (
|
164
178
|
query_result_checker.SqlResultValidator(
|
165
179
|
self._session,
|
166
|
-
|
180
|
+
(
|
181
|
+
f"CALL {system_func}("
|
182
|
+
f"'{self.fully_qualified_object_name(database_name, schema_name, service_name)}', '{instance_id}', "
|
183
|
+
f"'{container_name}')"
|
184
|
+
),
|
167
185
|
statement_params=statement_params,
|
168
186
|
)
|
169
187
|
.has_dimensions(expected_rows=1, expected_cols=1)
|
@@ -174,7 +192,9 @@ class ServiceSQLClient(_base._BaseSQLClient):
|
|
174
192
|
def get_service_status(
|
175
193
|
self,
|
176
194
|
*,
|
177
|
-
|
195
|
+
database_name: Optional[sql_identifier.SqlIdentifier],
|
196
|
+
schema_name: Optional[sql_identifier.SqlIdentifier],
|
197
|
+
service_name: sql_identifier.SqlIdentifier,
|
178
198
|
include_message: bool = False,
|
179
199
|
statement_params: Optional[Dict[str, Any]] = None,
|
180
200
|
) -> Tuple[ServiceStatus, Optional[str]]:
|
@@ -182,7 +202,7 @@ class ServiceSQLClient(_base._BaseSQLClient):
|
|
182
202
|
rows = (
|
183
203
|
query_result_checker.SqlResultValidator(
|
184
204
|
self._session,
|
185
|
-
f"CALL {system_func}('{service_name}')",
|
205
|
+
f"CALL {system_func}('{self.fully_qualified_object_name(database_name, schema_name, service_name)}')",
|
186
206
|
statement_params=statement_params,
|
187
207
|
)
|
188
208
|
.has_dimensions(expected_rows=1, expected_cols=1)
|
@@ -194,3 +214,17 @@ class ServiceSQLClient(_base._BaseSQLClient):
|
|
194
214
|
message = metadata["message"] if include_message else None
|
195
215
|
return service_status, message
|
196
216
|
return ServiceStatus.UNKNOWN, None
|
217
|
+
|
218
|
+
def drop_service(
|
219
|
+
self,
|
220
|
+
*,
|
221
|
+
database_name: Optional[sql_identifier.SqlIdentifier],
|
222
|
+
schema_name: Optional[sql_identifier.SqlIdentifier],
|
223
|
+
service_name: sql_identifier.SqlIdentifier,
|
224
|
+
statement_params: Optional[Dict[str, Any]] = None,
|
225
|
+
) -> None:
|
226
|
+
query_result_checker.SqlResultValidator(
|
227
|
+
self._session,
|
228
|
+
f"DROP SERVICE {self.fully_qualified_object_name(database_name, schema_name, service_name)}",
|
229
|
+
statement_params=statement_params,
|
230
|
+
).has_dimensions(expected_rows=1, expected_cols=1).validate()
|