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
@@ -1,212 +0,0 @@
1
- import http
2
- import logging
3
- from typing import Dict, Optional, cast
4
- from urllib.parse import urlunparse
5
-
6
- from snowflake.ml._internal.container_services.image_registry import (
7
- http_client as image_registry_http_client,
8
- imagelib,
9
- )
10
- from snowflake.ml._internal.exceptions import (
11
- error_codes,
12
- exceptions as snowml_exceptions,
13
- )
14
- from snowflake.snowpark import Session
15
- from snowflake.snowpark._internal import utils as snowpark_utils
16
-
17
- _MANIFEST_V1_HEADER = "application/vnd.oci.image.manifest.v1+json"
18
- _MANIFEST_V2_HEADER = "application/vnd.docker.distribution.manifest.v2+json"
19
- _SUPPORTED_MANIFEST_HEADERS = [_MANIFEST_V1_HEADER, _MANIFEST_V2_HEADER]
20
-
21
- logger = logging.getLogger(__name__)
22
-
23
-
24
- class ImageRegistryClient:
25
- """
26
- A partial implementation of an SPCS image registry client. The client utilizes the ImageRegistryHttpClient under
27
- the hood, incorporating a retry mechanism to handle intermittent 401 errors from the SPCS image registry.
28
- """
29
-
30
- def __init__(self, session: Session, full_dest_image_name: str) -> None:
31
- """Initialization
32
-
33
- Args:
34
- session: Snowpark session
35
- full_dest_image_name: Based on dest image name, repo url can be inferred.
36
- """
37
- self.image_registry_http_client = image_registry_http_client.ImageRegistryHttpClient(
38
- session=session,
39
- repo_url=self._convert_to_v2_manifests_url(full_image_name=full_dest_image_name),
40
- )
41
-
42
- def _convert_to_v2_manifests_url(self, full_image_name: str) -> str:
43
- """Converts a full image name to a Docker Registry HTTP API V2 URL:
44
- https://docs.docker.com/registry/spec/api/#existing-manifests
45
-
46
- org-account.registry-dev.snowflakecomputing.com/db/schema/repo/image_name:tag becomes
47
- https://org-account.registry-dev.snowflakecomputing.com/v2/db/schema/repo/image_name/manifests/tag
48
-
49
- Args:
50
- full_image_name: a string consists of image name and image tag.
51
-
52
- Returns:
53
- Docker HTTP V2 URL for checking manifest existence.
54
- """
55
- scheme = "https"
56
- full_image_name_parts = full_image_name.split(":")
57
- assert len(full_image_name_parts) == 2, "full image name should include both image name and tag"
58
-
59
- image_name = full_image_name_parts[0]
60
- tag = full_image_name_parts[1]
61
- image_name_parts = image_name.split("/")
62
- domain = image_name_parts[0]
63
- rest = "/".join(image_name_parts[1:])
64
- path = f"/v2/{rest}/manifests/{tag}"
65
- url_tuple = (scheme, domain, path, "", "", "")
66
- return urlunparse(url_tuple)
67
-
68
- def _get_accept_headers(self) -> Dict[str, str]:
69
- # Depending on the built image, the media type of the image manifest might be either
70
- # application/vnd.oci.image.manifest.v1+json or application/vnd.docker.distribution.manifest.v2+json
71
- # Hence we need to check for both, otherwise it could result in false negative.
72
- return {"Accept": ",".join(_SUPPORTED_MANIFEST_HEADERS)}
73
-
74
- def image_exists(self, full_image_name: str) -> bool:
75
- """Check whether image already exists in the registry.
76
-
77
- Args:
78
- full_image_name: Full image name consists of image name and image tag.
79
-
80
- Returns:
81
- Boolean value. True when image already exists, else False.
82
-
83
- """
84
- # When running in SPROC, the Sproc session connection will not have _rest object associated, which makes it
85
- # unable to fetch session token needed to authenticate to SPCS image registry.
86
- if snowpark_utils.is_in_stored_procedure(): # type: ignore[no-untyped-call]
87
- return False
88
- v2_api_url = self._convert_to_v2_manifests_url(full_image_name)
89
- headers = self._get_accept_headers()
90
- status = self.image_registry_http_client.head(v2_api_url, headers=headers).status_code
91
- return status == http.HTTPStatus.OK
92
-
93
- def _get_manifest(self, full_image_name: str) -> Dict[str, str]:
94
- """Retrieve image manifest file. Given Docker manifest comes with two versions, and for each version the
95
- corresponding request header is required for a successful HTTP response.
96
-
97
- Args:
98
- full_image_name: Full image name.
99
-
100
- Returns:
101
- Full manifest content as a python dict.
102
-
103
- Raises:
104
- SnowflakeMLException: when failed to retrieve manifest.
105
- """
106
-
107
- v2_api_url = self._convert_to_v2_manifests_url(full_image_name)
108
- res = self.image_registry_http_client.get(v2_api_url, headers=self._get_accept_headers())
109
- if res.status_code == http.HTTPStatus.OK:
110
- return cast(Dict[str, str], res.json())
111
- raise snowml_exceptions.SnowflakeMLException(
112
- error_code=error_codes.INTERNAL_SNOWFLAKE_IMAGE_REGISTRY_ERROR,
113
- original_exception=ValueError(
114
- f"Failed to retrieve manifest for {full_image_name}. \n"
115
- f"HTTP status code: {res.status_code}. Full response: {res.text}."
116
- ),
117
- )
118
-
119
- def add_tag_to_remote_image(self, original_full_image_name: str, new_tag: str) -> None:
120
- """Add a tag to an image in the registry.
121
-
122
- Args:
123
- original_full_image_name: The full image name is required to fetch manifest.
124
- new_tag: New tag to be added to the image.
125
-
126
- Returns:
127
- None
128
-
129
- Raises:
130
- SnowflakeMLException: when failed to push the newly updated manifest.
131
- """
132
-
133
- if snowpark_utils.is_in_stored_procedure(): # type: ignore[no-untyped-call]
134
- return None
135
-
136
- full_image_name_parts = original_full_image_name.split(":")
137
- assert len(full_image_name_parts) == 2, "full image name should include both image name and tag"
138
- new_full_image_name = ":".join([full_image_name_parts[0], new_tag])
139
- if self.image_exists(new_full_image_name):
140
- # Early return if image with the associated tag already exists.
141
- return
142
- api_url = self._convert_to_v2_manifests_url(new_full_image_name)
143
- manifest = self._get_manifest(full_image_name=original_full_image_name)
144
- manifest_copy = manifest.copy()
145
- manifest_copy["tag"] = new_tag
146
- headers = self._get_accept_headers()
147
- # Http Content-Type does not support multi-value, hence need to construct separate header.
148
- put_header_v1 = {
149
- **headers,
150
- "Content-Type": _MANIFEST_V1_HEADER,
151
- }
152
- put_header_v2 = {
153
- **headers,
154
- "Content-Type": _MANIFEST_V2_HEADER,
155
- }
156
-
157
- res1 = self.image_registry_http_client.put(api_url, headers=put_header_v1, json=manifest_copy)
158
- if res1.status_code != http.HTTPStatus.CREATED:
159
- res2 = self.image_registry_http_client.put(api_url, headers=put_header_v2, json=manifest_copy)
160
- if res2.status_code != http.HTTPStatus.CREATED:
161
- raise snowml_exceptions.SnowflakeMLException(
162
- error_code=error_codes.INTERNAL_SNOWFLAKE_IMAGE_REGISTRY_ERROR,
163
- original_exception=ValueError(
164
- f"Failed to push manifest for {new_full_image_name}. Two requests filed: \n"
165
- f"HTTP status code 1: {res1.status_code}. Full response 1: {res1.text}. \n"
166
- f"HTTP status code 2: {res2.status_code}. Full response 2: {res2.text}"
167
- ),
168
- )
169
- assert self.image_exists(
170
- new_full_image_name
171
- ), f"{new_full_image_name} should exist in image repo after a successful manifest update"
172
-
173
- def copy_image(
174
- self,
175
- source_image_with_digest: str,
176
- dest_image_with_tag: str,
177
- arch: Optional[imagelib._Arch] = None,
178
- ) -> None:
179
- """Util function to copy image across registry. Currently supported pulling from public docker image repo to
180
- SPCS image registry.
181
-
182
- Args:
183
- source_image_with_digest: source image with digest, e.g. gcr.io/kaniko-project/executor@sha256:b8c0977
184
- dest_image_with_tag: destination image with tag.
185
- arch: architecture of source image.
186
-
187
- Returns:
188
- None
189
- """
190
- logger.info(f"Copying image from {source_image_with_digest} to {dest_image_with_tag}")
191
- if snowpark_utils.is_in_stored_procedure(): # type: ignore[no-untyped-call]
192
- logger.warning(f"Running inside Sproc. Please ensure image already exists at {dest_image_with_tag}")
193
- return None
194
-
195
- arch = arch or imagelib._Arch("amd64", "linux")
196
-
197
- src_image = imagelib.convert_to_image_descriptor(source_image_with_digest, with_digest=True)
198
- dest_image = imagelib.convert_to_image_descriptor(
199
- dest_image_with_tag,
200
- with_tag=True,
201
- )
202
- # TODO[shchen]: Remove the imagelib, instead rely on the copy image system function later.
203
- imagelib.copy_image(
204
- src_image=src_image,
205
- dest_image=dest_image,
206
- arch=arch,
207
- src_retryable_http=image_registry_http_client.ImageRegistryHttpClient(
208
- repo_url=src_image.registry_name, no_cred=True
209
- ),
210
- dest_retryable_http=self.image_registry_http_client,
211
- )
212
- logger.info("Image copy completed successfully")
@@ -1,30 +0,0 @@
1
- import logging
2
- from typing import Optional
3
-
4
- logger = logging.getLogger(__name__)
5
-
6
-
7
- class LogStreamProcessor:
8
- def __init__(self) -> None:
9
- self.last_line_seen = 0
10
-
11
- def process_new_logs(self, job_logs: Optional[str], *, log_level: int = logging.INFO) -> None:
12
- if not job_logs:
13
- return
14
- log_entries = job_logs.split("\n")
15
- start_index = self.last_line_seen
16
- log_length = len(log_entries)
17
- for i in range(start_index, log_length):
18
- log_entry = log_entries[i]
19
- if log_level == logging.DEBUG:
20
- logger.debug(log_entry)
21
- elif log_level == logging.INFO:
22
- logger.info(log_entry)
23
- elif log_level == logging.WARNING:
24
- logger.warning(log_entry)
25
- elif log_level == logging.ERROR:
26
- logger.error(log_entry)
27
- elif log_level == logging.CRITICAL:
28
- logger.critical(log_entry)
29
-
30
- self.last_line_seen = log_length
@@ -1,46 +0,0 @@
1
- import base64
2
- import json
3
- from typing import TypedDict
4
-
5
- from snowflake import snowpark
6
-
7
-
8
- class SessionToken(TypedDict):
9
- token: str
10
- expires_in: str
11
-
12
-
13
- class SessionTokenManager:
14
- def __init__(self, session: snowpark.Session) -> None:
15
- self._session = session
16
-
17
- def get_session_token(self) -> SessionToken:
18
- """
19
- This function retrieves the session token from Snowpark session object.
20
-
21
- Returns:
22
- The session token string value.
23
- """
24
- ctx = self._session._conn._conn
25
- assert ctx._rest, "SnowflakeRestful is not set in session"
26
- token_data = ctx._rest._token_request("ISSUE")
27
- session_token = token_data["data"]["sessionToken"]
28
- validity_in_seconds = token_data["data"]["validityInSecondsST"]
29
- assert session_token, "session_token is not obtained successfully from the session object"
30
- assert validity_in_seconds, "validityInSecondsST is not obtained successfully from the session object"
31
- return {"token": session_token, "expires_in": validity_in_seconds}
32
-
33
- def get_base64_encoded_token(self, username: str = "0sessiontoken") -> str:
34
- """This function returns the base64 encoded username:password, which is compatible with registry, such as
35
- SnowService image registry, that uses Docker credential helper. In this case, password will be session token.
36
-
37
- Args:
38
- username: username for authentication.
39
-
40
- Returns:
41
- base64 encoded credential string.
42
-
43
- """
44
- credentials = f"{username}:{json.dumps(self.get_session_token())}"
45
- encoded_credentials = base64.b64encode(credentials.encode("utf-8")).decode("utf-8")
46
- return encoded_credentials
@@ -1,122 +0,0 @@
1
- import logging
2
- from datetime import datetime
3
- from typing import Any, Dict, Optional
4
-
5
- from snowflake import snowpark
6
- from snowflake.ml._internal import telemetry
7
- from snowflake.ml._internal.utils import query_result_checker
8
-
9
- logger = logging.getLogger(__name__)
10
-
11
- _DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S.%f %z"
12
- _COMPUTE_POOL = "compute_pool"
13
- _CREATED_ON = "created_on"
14
- _INSTANCE_FAMILY = "instance_family"
15
- _NAME = "name"
16
- _TELEMETRY_PROJECT = "MLOps"
17
- _TELEMETRY_SUBPROJECT = "SpcsDeployment"
18
- _SERVICE_START = "SPCS_SERVICE_START"
19
- _SERVICE_END = "SPCS_SERVICE_END"
20
-
21
-
22
- def _desc_compute_pool(session: snowpark.Session, compute_pool_name: str) -> Dict[str, Any]:
23
- sql = f"DESC COMPUTE POOL {compute_pool_name}"
24
- result = (
25
- query_result_checker.SqlResultValidator(
26
- session=session,
27
- query=sql,
28
- )
29
- .has_column(_INSTANCE_FAMILY)
30
- .has_column(_NAME)
31
- .has_dimensions(expected_rows=1)
32
- .validate()
33
- )
34
- return result[0].as_dict()
35
-
36
-
37
- def _desc_service(session: snowpark.Session, fully_qualified_name: str) -> Dict[str, Any]:
38
- sql = f"DESC SERVICE {fully_qualified_name}"
39
- result = (
40
- query_result_checker.SqlResultValidator(
41
- session=session,
42
- query=sql,
43
- )
44
- .has_column(_COMPUTE_POOL)
45
- .has_dimensions(expected_rows=1)
46
- .validate()
47
- )
48
- return result[0].as_dict()
49
-
50
-
51
- def _get_current_time() -> datetime:
52
- """
53
- This method exists to make it easier to mock datetime in test.
54
-
55
- Returns:
56
- current datetime
57
- """
58
- return datetime.now()
59
-
60
-
61
- def _send_service_telemetry(
62
- fully_qualified_name: Optional[str] = None,
63
- compute_pool_name: Optional[str] = None,
64
- service_details: Optional[Dict[str, Any]] = None,
65
- compute_pool_details: Optional[Dict[str, Any]] = None,
66
- duration_in_seconds: Optional[int] = None,
67
- kwargs: Optional[Dict[str, Any]] = None,
68
- ) -> None:
69
- try:
70
- telemetry.send_custom_usage(
71
- project=_TELEMETRY_PROJECT,
72
- subproject=_TELEMETRY_SUBPROJECT,
73
- telemetry_type=telemetry.TelemetryField.TYPE_SNOWML_SPCS_USAGE.value,
74
- data={
75
- "service_name": fully_qualified_name,
76
- "compute_pool_name": compute_pool_name,
77
- "service_details": service_details,
78
- "compute_pool_details": compute_pool_details,
79
- "duration_in_seconds": duration_in_seconds,
80
- },
81
- kwargs=kwargs,
82
- )
83
- except Exception as e:
84
- logger.error(f"Failed to send service telemetry: {e}")
85
-
86
-
87
- def record_service_start(session: snowpark.Session, fully_qualified_name: str) -> None:
88
- service_details = _desc_service(session, fully_qualified_name)
89
- compute_pool_name = service_details[_COMPUTE_POOL]
90
- compute_pool_details = _desc_compute_pool(session, compute_pool_name)
91
-
92
- _send_service_telemetry(
93
- fully_qualified_name=fully_qualified_name,
94
- compute_pool_name=compute_pool_name,
95
- service_details=service_details,
96
- compute_pool_details=compute_pool_details,
97
- kwargs={telemetry.TelemetryField.KEY_CUSTOM_TAGS.value: _SERVICE_START},
98
- )
99
-
100
- logger.info(f"Service {fully_qualified_name} created with compute pool {compute_pool_name}.")
101
-
102
-
103
- def record_service_end(session: snowpark.Session, fully_qualified_name: str) -> None:
104
- service_details = _desc_service(session, fully_qualified_name)
105
- compute_pool_details = _desc_compute_pool(session, service_details[_COMPUTE_POOL])
106
- compute_pool_name = service_details[_COMPUTE_POOL]
107
-
108
- created_on_datetime: datetime = service_details[_CREATED_ON]
109
- current_time: datetime = _get_current_time()
110
- current_time = current_time.replace(tzinfo=created_on_datetime.tzinfo)
111
- duration_in_seconds = int((current_time - created_on_datetime).total_seconds())
112
-
113
- _send_service_telemetry(
114
- fully_qualified_name=fully_qualified_name,
115
- compute_pool_name=compute_pool_name,
116
- service_details=service_details,
117
- compute_pool_details=compute_pool_details,
118
- duration_in_seconds=duration_in_seconds,
119
- kwargs={telemetry.TelemetryField.KEY_CUSTOM_TAGS.value: _SERVICE_END},
120
- )
121
-
122
- logger.info(f"Service {fully_qualified_name} deleted from compute pool {compute_pool_name}")
@@ -1,77 +0,0 @@
1
- import posixpath
2
- from typing import Optional, Tuple
3
- from urllib.parse import ParseResult, urlparse, urlunparse
4
-
5
- from snowflake.ml._internal.utils import identifier
6
-
7
- _LOCAL_URI_SCHEMES = ["", "file"]
8
- _HTTP_URI_SCHEMES = ["http", "https"]
9
- _SNOWFLAKE_STAGE_URI_SCHEMES = ["sfc", "sfstage"]
10
-
11
-
12
- def is_local_uri(uri: str) -> bool:
13
- """Returns true if the URI has a scheme that indicates a local file."""
14
- return urlparse(uri).scheme in _LOCAL_URI_SCHEMES
15
-
16
-
17
- def is_http_uri(uri: str) -> bool:
18
- """Returns true if the URI has a scheme that indicates a web (http,https) address."""
19
- return urlparse(uri).scheme in _HTTP_URI_SCHEMES
20
-
21
-
22
- def is_snowflake_stage_uri(uri: str) -> bool:
23
- """Returns true if the URI is a scheme that indicates a Snowflake stage location."""
24
- return urlparse(uri).scheme in _SNOWFLAKE_STAGE_URI_SCHEMES
25
-
26
-
27
- def get_snowflake_stage_path_from_uri(uri: str) -> Optional[str]:
28
- """Returns the stage path pointed by the URI.
29
-
30
- Args:
31
- uri: URI for which stage file is needed.
32
-
33
- Returns:
34
- The Snowflake stage location encoded by the given URI. Returns None if the URI is not pointing to a Snowflake
35
- stage.
36
- """
37
- if not is_snowflake_stage_uri(uri):
38
- return None
39
- uri_components = urlparse(uri)
40
- # posixpath.join will drop other components if any of arguments is absolute path.
41
- # The path we get is actually absolute (starting with '/'), however, since we concat them to stage location,
42
- # it should not.
43
- return posixpath.normpath(
44
- posixpath.join(posixpath.normpath(uri_components.netloc), posixpath.normpath(uri_components.path.lstrip("/")))
45
- )
46
-
47
-
48
- def get_uri_scheme(uri: str) -> str:
49
- """Returns the scheme for the given URI."""
50
- return urlparse(uri).scheme
51
-
52
-
53
- def get_uri_from_snowflake_stage_path(stage_path: str) -> str:
54
- """Generates a URI from Snowflake stage path."""
55
- assert stage_path.startswith("@")
56
- (db, schema, stage, path) = identifier.parse_snowflake_stage_path(
57
- posixpath.normpath(identifier.remove_prefix(stage_path, "@"))
58
- )
59
- return urlunparse(
60
- ParseResult(
61
- scheme=_SNOWFLAKE_STAGE_URI_SCHEMES[0],
62
- netloc=identifier.get_schema_level_object_identifier(db, schema, stage),
63
- path=path,
64
- params="",
65
- query="",
66
- fragment="",
67
- )
68
- )
69
-
70
-
71
- def get_stage_and_path(stage_path: str) -> Tuple[str, str]:
72
- assert stage_path.startswith("@"), f"stage path should start with @, actual: {stage_path}"
73
- (db, schema, stage, path) = identifier.parse_snowflake_stage_path(
74
- posixpath.normpath(identifier.remove_prefix(stage_path, "@"))
75
- )
76
- full_qualified_stage = "@" + identifier.get_schema_level_object_identifier(db, schema, stage)
77
- return full_qualified_stage, path.lstrip("/")