snowflake-ml-python 1.4.0__py3-none-any.whl → 1.5.0__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 (234) hide show
  1. snowflake/ml/_internal/env_utils.py +77 -32
  2. snowflake/ml/_internal/exceptions/dataset_error_messages.py +5 -0
  3. snowflake/ml/_internal/exceptions/dataset_errors.py +24 -0
  4. snowflake/ml/_internal/exceptions/error_codes.py +3 -0
  5. snowflake/ml/_internal/lineage/data_source.py +10 -0
  6. snowflake/ml/_internal/lineage/dataset_dataframe.py +44 -0
  7. snowflake/ml/_internal/utils/identifier.py +3 -1
  8. snowflake/ml/_internal/utils/sql_identifier.py +2 -6
  9. snowflake/ml/dataset/__init__.py +10 -0
  10. snowflake/ml/dataset/dataset.py +454 -129
  11. snowflake/ml/dataset/dataset_factory.py +53 -0
  12. snowflake/ml/dataset/dataset_metadata.py +103 -0
  13. snowflake/ml/dataset/dataset_reader.py +202 -0
  14. snowflake/ml/feature_store/feature_store.py +531 -332
  15. snowflake/ml/feature_store/feature_view.py +40 -23
  16. snowflake/ml/fileset/embedded_stage_fs.py +146 -0
  17. snowflake/ml/fileset/sfcfs.py +56 -54
  18. snowflake/ml/fileset/snowfs.py +159 -0
  19. snowflake/ml/fileset/stage_fs.py +49 -17
  20. snowflake/ml/model/__init__.py +2 -2
  21. snowflake/ml/model/_api.py +16 -1
  22. snowflake/ml/model/_client/model/model_impl.py +27 -0
  23. snowflake/ml/model/_client/model/model_version_impl.py +137 -50
  24. snowflake/ml/model/_client/ops/model_ops.py +159 -40
  25. snowflake/ml/model/_client/sql/model.py +25 -2
  26. snowflake/ml/model/_client/sql/model_version.py +131 -2
  27. snowflake/ml/model/_deploy_client/image_builds/server_image_builder.py +5 -1
  28. snowflake/ml/model/_deploy_client/image_builds/templates/dockerfile_template +1 -0
  29. snowflake/ml/model/_deploy_client/snowservice/deploy.py +2 -0
  30. snowflake/ml/model/_deploy_client/utils/constants.py +0 -5
  31. snowflake/ml/model/_deploy_client/utils/snowservice_client.py +21 -50
  32. snowflake/ml/model/_model_composer/model_composer.py +22 -1
  33. snowflake/ml/model/_model_composer/model_manifest/model_manifest.py +38 -51
  34. snowflake/ml/model/_model_composer/model_manifest/model_manifest_schema.py +19 -1
  35. snowflake/ml/model/_model_composer/model_method/model_method.py +6 -10
  36. snowflake/ml/model/_packager/model_env/model_env.py +41 -0
  37. snowflake/ml/model/_packager/model_handlers/catboost.py +206 -0
  38. snowflake/ml/model/_packager/model_handlers/lightgbm.py +218 -0
  39. snowflake/ml/model/_packager/model_handlers/sklearn.py +3 -0
  40. snowflake/ml/model/_packager/model_meta/_core_requirements.py +1 -1
  41. snowflake/ml/model/_packager/model_meta/model_meta.py +37 -11
  42. snowflake/ml/model/_packager/model_meta/model_meta_schema.py +20 -1
  43. snowflake/ml/model/_packager/model_meta_migrator/migrator_plans.py +3 -1
  44. snowflake/ml/model/_packager/model_packager.py +2 -5
  45. snowflake/ml/model/{_model_composer/model_runtime/_runtime_requirements.py → _packager/model_runtime/_snowml_inference_alternative_requirements.py} +1 -1
  46. snowflake/ml/model/_packager/model_runtime/model_runtime.py +137 -0
  47. snowflake/ml/model/type_hints.py +21 -2
  48. snowflake/ml/modeling/_internal/estimator_utils.py +16 -11
  49. snowflake/ml/modeling/_internal/local_implementations/pandas_handlers.py +4 -1
  50. snowflake/ml/modeling/_internal/local_implementations/pandas_trainer.py +55 -3
  51. snowflake/ml/modeling/_internal/ml_runtime_implementations/ml_runtime_handlers.py +34 -18
  52. snowflake/ml/modeling/_internal/model_trainer.py +7 -0
  53. snowflake/ml/modeling/_internal/model_trainer_builder.py +42 -9
  54. snowflake/ml/modeling/_internal/snowpark_implementations/distributed_hpo_trainer.py +13 -14
  55. snowflake/ml/modeling/_internal/snowpark_implementations/snowpark_handlers.py +29 -7
  56. snowflake/ml/modeling/_internal/snowpark_implementations/snowpark_trainer.py +261 -16
  57. snowflake/ml/modeling/calibration/calibrated_classifier_cv.py +246 -175
  58. snowflake/ml/modeling/cluster/affinity_propagation.py +246 -175
  59. snowflake/ml/modeling/cluster/agglomerative_clustering.py +246 -175
  60. snowflake/ml/modeling/cluster/birch.py +248 -175
  61. snowflake/ml/modeling/cluster/bisecting_k_means.py +248 -175
  62. snowflake/ml/modeling/cluster/dbscan.py +246 -175
  63. snowflake/ml/modeling/cluster/feature_agglomeration.py +248 -175
  64. snowflake/ml/modeling/cluster/k_means.py +248 -175
  65. snowflake/ml/modeling/cluster/mean_shift.py +246 -175
  66. snowflake/ml/modeling/cluster/mini_batch_k_means.py +248 -175
  67. snowflake/ml/modeling/cluster/optics.py +246 -175
  68. snowflake/ml/modeling/cluster/spectral_biclustering.py +246 -175
  69. snowflake/ml/modeling/cluster/spectral_clustering.py +246 -175
  70. snowflake/ml/modeling/cluster/spectral_coclustering.py +246 -175
  71. snowflake/ml/modeling/compose/column_transformer.py +248 -175
  72. snowflake/ml/modeling/compose/transformed_target_regressor.py +246 -175
  73. snowflake/ml/modeling/covariance/elliptic_envelope.py +246 -175
  74. snowflake/ml/modeling/covariance/empirical_covariance.py +246 -175
  75. snowflake/ml/modeling/covariance/graphical_lasso.py +246 -175
  76. snowflake/ml/modeling/covariance/graphical_lasso_cv.py +246 -175
  77. snowflake/ml/modeling/covariance/ledoit_wolf.py +246 -175
  78. snowflake/ml/modeling/covariance/min_cov_det.py +246 -175
  79. snowflake/ml/modeling/covariance/oas.py +246 -175
  80. snowflake/ml/modeling/covariance/shrunk_covariance.py +246 -175
  81. snowflake/ml/modeling/decomposition/dictionary_learning.py +248 -175
  82. snowflake/ml/modeling/decomposition/factor_analysis.py +248 -175
  83. snowflake/ml/modeling/decomposition/fast_ica.py +248 -175
  84. snowflake/ml/modeling/decomposition/incremental_pca.py +248 -175
  85. snowflake/ml/modeling/decomposition/kernel_pca.py +248 -175
  86. snowflake/ml/modeling/decomposition/mini_batch_dictionary_learning.py +248 -175
  87. snowflake/ml/modeling/decomposition/mini_batch_sparse_pca.py +248 -175
  88. snowflake/ml/modeling/decomposition/pca.py +248 -175
  89. snowflake/ml/modeling/decomposition/sparse_pca.py +248 -175
  90. snowflake/ml/modeling/decomposition/truncated_svd.py +248 -175
  91. snowflake/ml/modeling/discriminant_analysis/linear_discriminant_analysis.py +248 -175
  92. snowflake/ml/modeling/discriminant_analysis/quadratic_discriminant_analysis.py +246 -175
  93. snowflake/ml/modeling/ensemble/ada_boost_classifier.py +246 -175
  94. snowflake/ml/modeling/ensemble/ada_boost_regressor.py +246 -175
  95. snowflake/ml/modeling/ensemble/bagging_classifier.py +246 -175
  96. snowflake/ml/modeling/ensemble/bagging_regressor.py +246 -175
  97. snowflake/ml/modeling/ensemble/extra_trees_classifier.py +246 -175
  98. snowflake/ml/modeling/ensemble/extra_trees_regressor.py +246 -175
  99. snowflake/ml/modeling/ensemble/gradient_boosting_classifier.py +246 -175
  100. snowflake/ml/modeling/ensemble/gradient_boosting_regressor.py +246 -175
  101. snowflake/ml/modeling/ensemble/hist_gradient_boosting_classifier.py +246 -175
  102. snowflake/ml/modeling/ensemble/hist_gradient_boosting_regressor.py +246 -175
  103. snowflake/ml/modeling/ensemble/isolation_forest.py +246 -175
  104. snowflake/ml/modeling/ensemble/random_forest_classifier.py +246 -175
  105. snowflake/ml/modeling/ensemble/random_forest_regressor.py +246 -175
  106. snowflake/ml/modeling/ensemble/stacking_regressor.py +248 -175
  107. snowflake/ml/modeling/ensemble/voting_classifier.py +248 -175
  108. snowflake/ml/modeling/ensemble/voting_regressor.py +248 -175
  109. snowflake/ml/modeling/feature_selection/generic_univariate_select.py +248 -175
  110. snowflake/ml/modeling/feature_selection/select_fdr.py +248 -175
  111. snowflake/ml/modeling/feature_selection/select_fpr.py +248 -175
  112. snowflake/ml/modeling/feature_selection/select_fwe.py +248 -175
  113. snowflake/ml/modeling/feature_selection/select_k_best.py +248 -175
  114. snowflake/ml/modeling/feature_selection/select_percentile.py +248 -175
  115. snowflake/ml/modeling/feature_selection/sequential_feature_selector.py +248 -175
  116. snowflake/ml/modeling/feature_selection/variance_threshold.py +248 -175
  117. snowflake/ml/modeling/framework/_utils.py +8 -1
  118. snowflake/ml/modeling/framework/base.py +72 -37
  119. snowflake/ml/modeling/gaussian_process/gaussian_process_classifier.py +246 -175
  120. snowflake/ml/modeling/gaussian_process/gaussian_process_regressor.py +246 -175
  121. snowflake/ml/modeling/impute/iterative_imputer.py +248 -175
  122. snowflake/ml/modeling/impute/knn_imputer.py +248 -175
  123. snowflake/ml/modeling/impute/missing_indicator.py +248 -175
  124. snowflake/ml/modeling/kernel_approximation/additive_chi2_sampler.py +248 -175
  125. snowflake/ml/modeling/kernel_approximation/nystroem.py +248 -175
  126. snowflake/ml/modeling/kernel_approximation/polynomial_count_sketch.py +248 -175
  127. snowflake/ml/modeling/kernel_approximation/rbf_sampler.py +248 -175
  128. snowflake/ml/modeling/kernel_approximation/skewed_chi2_sampler.py +248 -175
  129. snowflake/ml/modeling/kernel_ridge/kernel_ridge.py +246 -175
  130. snowflake/ml/modeling/lightgbm/lgbm_classifier.py +246 -175
  131. snowflake/ml/modeling/lightgbm/lgbm_regressor.py +246 -175
  132. snowflake/ml/modeling/linear_model/ard_regression.py +246 -175
  133. snowflake/ml/modeling/linear_model/bayesian_ridge.py +246 -175
  134. snowflake/ml/modeling/linear_model/elastic_net.py +246 -175
  135. snowflake/ml/modeling/linear_model/elastic_net_cv.py +246 -175
  136. snowflake/ml/modeling/linear_model/gamma_regressor.py +246 -175
  137. snowflake/ml/modeling/linear_model/huber_regressor.py +246 -175
  138. snowflake/ml/modeling/linear_model/lars.py +246 -175
  139. snowflake/ml/modeling/linear_model/lars_cv.py +246 -175
  140. snowflake/ml/modeling/linear_model/lasso.py +246 -175
  141. snowflake/ml/modeling/linear_model/lasso_cv.py +246 -175
  142. snowflake/ml/modeling/linear_model/lasso_lars.py +246 -175
  143. snowflake/ml/modeling/linear_model/lasso_lars_cv.py +246 -175
  144. snowflake/ml/modeling/linear_model/lasso_lars_ic.py +246 -175
  145. snowflake/ml/modeling/linear_model/linear_regression.py +246 -175
  146. snowflake/ml/modeling/linear_model/logistic_regression.py +246 -175
  147. snowflake/ml/modeling/linear_model/logistic_regression_cv.py +246 -175
  148. snowflake/ml/modeling/linear_model/multi_task_elastic_net.py +246 -175
  149. snowflake/ml/modeling/linear_model/multi_task_elastic_net_cv.py +246 -175
  150. snowflake/ml/modeling/linear_model/multi_task_lasso.py +246 -175
  151. snowflake/ml/modeling/linear_model/multi_task_lasso_cv.py +246 -175
  152. snowflake/ml/modeling/linear_model/orthogonal_matching_pursuit.py +246 -175
  153. snowflake/ml/modeling/linear_model/passive_aggressive_classifier.py +246 -175
  154. snowflake/ml/modeling/linear_model/passive_aggressive_regressor.py +246 -175
  155. snowflake/ml/modeling/linear_model/perceptron.py +246 -175
  156. snowflake/ml/modeling/linear_model/poisson_regressor.py +246 -175
  157. snowflake/ml/modeling/linear_model/ransac_regressor.py +246 -175
  158. snowflake/ml/modeling/linear_model/ridge.py +246 -175
  159. snowflake/ml/modeling/linear_model/ridge_classifier.py +246 -175
  160. snowflake/ml/modeling/linear_model/ridge_classifier_cv.py +246 -175
  161. snowflake/ml/modeling/linear_model/ridge_cv.py +246 -175
  162. snowflake/ml/modeling/linear_model/sgd_classifier.py +246 -175
  163. snowflake/ml/modeling/linear_model/sgd_one_class_svm.py +246 -175
  164. snowflake/ml/modeling/linear_model/sgd_regressor.py +246 -175
  165. snowflake/ml/modeling/linear_model/theil_sen_regressor.py +246 -175
  166. snowflake/ml/modeling/linear_model/tweedie_regressor.py +246 -175
  167. snowflake/ml/modeling/manifold/isomap.py +248 -175
  168. snowflake/ml/modeling/manifold/mds.py +248 -175
  169. snowflake/ml/modeling/manifold/spectral_embedding.py +248 -175
  170. snowflake/ml/modeling/manifold/tsne.py +248 -175
  171. snowflake/ml/modeling/mixture/bayesian_gaussian_mixture.py +246 -175
  172. snowflake/ml/modeling/mixture/gaussian_mixture.py +246 -175
  173. snowflake/ml/modeling/model_selection/grid_search_cv.py +63 -41
  174. snowflake/ml/modeling/model_selection/randomized_search_cv.py +80 -38
  175. snowflake/ml/modeling/multiclass/one_vs_one_classifier.py +246 -175
  176. snowflake/ml/modeling/multiclass/one_vs_rest_classifier.py +246 -175
  177. snowflake/ml/modeling/multiclass/output_code_classifier.py +246 -175
  178. snowflake/ml/modeling/naive_bayes/bernoulli_nb.py +246 -175
  179. snowflake/ml/modeling/naive_bayes/categorical_nb.py +246 -175
  180. snowflake/ml/modeling/naive_bayes/complement_nb.py +246 -175
  181. snowflake/ml/modeling/naive_bayes/gaussian_nb.py +246 -175
  182. snowflake/ml/modeling/naive_bayes/multinomial_nb.py +246 -175
  183. snowflake/ml/modeling/neighbors/k_neighbors_classifier.py +246 -175
  184. snowflake/ml/modeling/neighbors/k_neighbors_regressor.py +246 -175
  185. snowflake/ml/modeling/neighbors/kernel_density.py +246 -175
  186. snowflake/ml/modeling/neighbors/local_outlier_factor.py +246 -175
  187. snowflake/ml/modeling/neighbors/nearest_centroid.py +246 -175
  188. snowflake/ml/modeling/neighbors/nearest_neighbors.py +246 -175
  189. snowflake/ml/modeling/neighbors/neighborhood_components_analysis.py +248 -175
  190. snowflake/ml/modeling/neighbors/radius_neighbors_classifier.py +246 -175
  191. snowflake/ml/modeling/neighbors/radius_neighbors_regressor.py +246 -175
  192. snowflake/ml/modeling/neural_network/bernoulli_rbm.py +248 -175
  193. snowflake/ml/modeling/neural_network/mlp_classifier.py +246 -175
  194. snowflake/ml/modeling/neural_network/mlp_regressor.py +246 -175
  195. snowflake/ml/modeling/pipeline/pipeline.py +517 -35
  196. snowflake/ml/modeling/preprocessing/binarizer.py +1 -5
  197. snowflake/ml/modeling/preprocessing/k_bins_discretizer.py +1 -5
  198. snowflake/ml/modeling/preprocessing/label_encoder.py +1 -5
  199. snowflake/ml/modeling/preprocessing/max_abs_scaler.py +1 -5
  200. snowflake/ml/modeling/preprocessing/min_max_scaler.py +10 -12
  201. snowflake/ml/modeling/preprocessing/normalizer.py +1 -5
  202. snowflake/ml/modeling/preprocessing/one_hot_encoder.py +13 -5
  203. snowflake/ml/modeling/preprocessing/ordinal_encoder.py +1 -5
  204. snowflake/ml/modeling/preprocessing/polynomial_features.py +248 -175
  205. snowflake/ml/modeling/preprocessing/robust_scaler.py +1 -5
  206. snowflake/ml/modeling/preprocessing/standard_scaler.py +11 -11
  207. snowflake/ml/modeling/semi_supervised/label_propagation.py +246 -175
  208. snowflake/ml/modeling/semi_supervised/label_spreading.py +246 -175
  209. snowflake/ml/modeling/svm/linear_svc.py +246 -175
  210. snowflake/ml/modeling/svm/linear_svr.py +246 -175
  211. snowflake/ml/modeling/svm/nu_svc.py +246 -175
  212. snowflake/ml/modeling/svm/nu_svr.py +246 -175
  213. snowflake/ml/modeling/svm/svc.py +246 -175
  214. snowflake/ml/modeling/svm/svr.py +246 -175
  215. snowflake/ml/modeling/tree/decision_tree_classifier.py +246 -175
  216. snowflake/ml/modeling/tree/decision_tree_regressor.py +246 -175
  217. snowflake/ml/modeling/tree/extra_tree_classifier.py +246 -175
  218. snowflake/ml/modeling/tree/extra_tree_regressor.py +246 -175
  219. snowflake/ml/modeling/xgboost/xgb_classifier.py +246 -175
  220. snowflake/ml/modeling/xgboost/xgb_regressor.py +246 -175
  221. snowflake/ml/modeling/xgboost/xgbrf_classifier.py +246 -175
  222. snowflake/ml/modeling/xgboost/xgbrf_regressor.py +246 -175
  223. snowflake/ml/registry/model_registry.py +3 -149
  224. snowflake/ml/registry/registry.py +1 -1
  225. snowflake/ml/version.py +1 -1
  226. {snowflake_ml_python-1.4.0.dist-info → snowflake_ml_python-1.5.0.dist-info}/METADATA +129 -57
  227. snowflake_ml_python-1.5.0.dist-info/RECORD +380 -0
  228. snowflake/ml/model/_model_composer/model_runtime/model_runtime.py +0 -97
  229. snowflake/ml/registry/_artifact_manager.py +0 -156
  230. snowflake/ml/registry/artifact.py +0 -46
  231. snowflake_ml_python-1.4.0.dist-info/RECORD +0 -370
  232. {snowflake_ml_python-1.4.0.dist-info → snowflake_ml_python-1.5.0.dist-info}/LICENSE.txt +0 -0
  233. {snowflake_ml_python-1.4.0.dist-info → snowflake_ml_python-1.5.0.dist-info}/WHEEL +0 -0
  234. {snowflake_ml_python-1.4.0.dist-info → snowflake_ml_python-1.5.0.dist-info}/top_level.txt +0 -0
@@ -8,7 +8,7 @@ import fsspec
8
8
  from fsspec.implementations import http as httpfs
9
9
 
10
10
  from snowflake import snowpark
11
- from snowflake.connector import connection
11
+ from snowflake.connector import connection, errorcode
12
12
  from snowflake.ml._internal import telemetry
13
13
  from snowflake.ml._internal.exceptions import (
14
14
  error_codes,
@@ -17,6 +17,7 @@ from snowflake.ml._internal.exceptions import (
17
17
  fileset_errors,
18
18
  )
19
19
  from snowflake.snowpark import exceptions as snowpark_exceptions
20
+ from snowflake.snowpark._internal import utils as snowpark_utils
20
21
 
21
22
  # The default length of how long a presigned url stays active in seconds.
22
23
  # Presigned url here is used to fetch file objects from Snowflake when SFStageFileSystem.open() is called.
@@ -79,7 +80,9 @@ class SFStageFileSystem(fsspec.AbstractFileSystem):
79
80
  # None -> Try pre-signed URL access, fall back to file download
80
81
  # True -> Use file download path without trying pre-signed URL access
81
82
  # False -> Use pre-signed URL access, skip download fallback on failure
82
- _USE_FALLBACK_FILE_ACCESS = None
83
+ _USE_FALLBACK_FILE_ACCESS = (
84
+ True if snowpark_utils.is_in_stored_procedure() else None # type: ignore[no-untyped-call]
85
+ )
83
86
 
84
87
  def __init__(
85
88
  self,
@@ -141,7 +144,6 @@ class SFStageFileSystem(fsspec.AbstractFileSystem):
141
144
  project=_PROJECT,
142
145
  func_params_to_log=["detail"],
143
146
  )
144
- @snowpark._internal.utils.private_preview(version="0.2.0")
145
147
  def ls(self, path: str, detail: bool = False) -> Union[List[str], List[Dict[str, Any]]]:
146
148
  """Override fsspec `ls` method. List single "directory" with or without details.
147
149
 
@@ -164,7 +166,8 @@ class SFStageFileSystem(fsspec.AbstractFileSystem):
164
166
  """
165
167
  try:
166
168
  loc = self.stage_name
167
- objects = self._session.sql(f"LIST {loc}/{path}").collect()
169
+ path = path.lstrip("/")
170
+ objects = self._session.sql(f"LIST '{loc}/{path}'").collect()
168
171
  except snowpark_exceptions.SnowparkClientException as e:
169
172
  if e.message.startswith(fileset_errors.ERRNO_DOMAIN_NOT_EXIST):
170
173
  raise snowml_exceptions.SnowflakeMLException(
@@ -187,7 +190,6 @@ class SFStageFileSystem(fsspec.AbstractFileSystem):
187
190
  @telemetry.send_api_usage_telemetry(
188
191
  project=_PROJECT,
189
192
  )
190
- @snowpark._internal.utils.private_preview(version="0.2.0")
191
193
  def optimize_read(self, files: Optional[List[str]] = None) -> None:
192
194
  """Prefetch and cache the presigned urls for all the given files to speed up the read performance.
193
195
 
@@ -214,7 +216,6 @@ class SFStageFileSystem(fsspec.AbstractFileSystem):
214
216
  @telemetry.send_api_usage_telemetry(
215
217
  project=_PROJECT,
216
218
  )
217
- @snowpark._internal.utils.private_preview(version="0.2.0")
218
219
  def _open(self, path: str, mode: str = "rb", **kwargs: Any) -> fsspec.spec.AbstractBufferedFile:
219
220
  """Override fsspec `_open` method. Open a file for reading.
220
221
 
@@ -234,7 +235,7 @@ class SFStageFileSystem(fsspec.AbstractFileSystem):
234
235
  """
235
236
  path = path.lstrip("/")
236
237
  if self._USE_FALLBACK_FILE_ACCESS:
237
- return self._session.file.get_stream(f"{self.stage_name}/{path}")
238
+ return self._open_with_snowpark(path)
238
239
  cached_presigned_url = self._url_cache.get(path, None)
239
240
  if not cached_presigned_url:
240
241
  res = self._fetch_presigned_urls([path])
@@ -252,19 +253,42 @@ class SFStageFileSystem(fsspec.AbstractFileSystem):
252
253
  except FileNotFoundError:
253
254
  # Enable fallback if _USE_FALLBACK_FILE_ACCESS is True or None; set to False to disable
254
255
  if self._USE_FALLBACK_FILE_ACCESS != False: # noqa: E712
255
- try:
256
- # Try falling back to Snowpark file read if presigned URL access failed
257
- # If fallback is successful, most likely in sproc without External Access Integration
258
- content = self._session.file.get_stream(f"{self.stage_name}/{path}")
259
- self._USE_FALLBACK_FILE_ACCESS = True
260
- return content
261
- except Exception:
262
- pass
256
+ content = self._open_with_snowpark(path)
257
+ self._USE_FALLBACK_FILE_ACCESS = True
258
+ return content
263
259
  raise snowml_exceptions.SnowflakeMLException(
264
260
  error_code=error_codes.SNOWML_NOT_FOUND,
265
261
  original_exception=fileset_errors.StageFileNotFoundError(f"Stage file {path} doesn't exist."),
266
262
  )
267
263
 
264
+ def _open_with_snowpark(self, path: str, **kwargs: Dict[str, Any]) -> fsspec.spec.AbstractBufferedFile:
265
+ """Open the a file for reading using snowflake.snowpark.file_operation
266
+
267
+ Args:
268
+ path: Path of file in Snowflake stage.
269
+ **kwargs: Extra options to pass to snowflake.snowpark.file_operation.get_stream
270
+
271
+ Returns:
272
+ A fsspec file-like object.
273
+
274
+ Raises:
275
+ SnowflakeMLException: An error occurred when the given path points to a file that cannot be found.
276
+ SnowflakeMLException: An unknown Snowpark error occurred during file read.
277
+ """
278
+ try:
279
+ return self._session.file.get_stream(f"{self.stage_name}/{path}", **kwargs)
280
+ except snowpark_exceptions.SnowparkSQLException as e:
281
+ if _match_error_code(e, errorcode.ER_FILE_NOT_EXISTS):
282
+ raise snowml_exceptions.SnowflakeMLException(
283
+ error_code=error_codes.SNOWML_NOT_FOUND,
284
+ original_exception=fileset_errors.StageFileNotFoundError(f"Stage file {path} doesn't exist."),
285
+ )
286
+ else:
287
+ raise snowml_exceptions.SnowflakeMLException(
288
+ error_code=error_codes.INTERNAL_SNOWPARK_ERROR,
289
+ original_exception=e,
290
+ )
291
+
268
292
  def _parse_list_result(
269
293
  self, list_result: List[Tuple[str, int, str, str]], search_path: str
270
294
  ) -> List[Dict[str, Any]]:
@@ -352,7 +376,7 @@ class SFStageFileSystem(fsspec.AbstractFileSystem):
352
376
  file_df = self._session.create_dataframe(files).to_df("name")
353
377
  try:
354
378
  presigned_urls: List[Tuple[str, str]] = file_df.select_expr(
355
- f"name, get_presigned_url({self.stage_name}, name, {url_lifetime}) as url"
379
+ f"name, get_presigned_url('{self.stage_name}', name, {url_lifetime}) as url"
356
380
  ).collect(
357
381
  statement_params=telemetry.get_function_usage_statement_params(
358
382
  project=_PROJECT,
@@ -363,7 +387,9 @@ class SFStageFileSystem(fsspec.AbstractFileSystem):
363
387
  ),
364
388
  )
365
389
  except snowpark_exceptions.SnowparkClientException as e:
366
- if e.message.startswith(fileset_errors.ERRNO_STAGE_NOT_EXIST):
390
+ if e.message.startswith(fileset_errors.ERRNO_DOMAIN_NOT_EXIST) or e.message.startswith(
391
+ fileset_errors.ERRNO_STAGE_NOT_EXIST
392
+ ):
367
393
  raise snowml_exceptions.SnowflakeMLException(
368
394
  error_code=error_codes.SNOWML_NOT_FOUND,
369
395
  original_exception=fileset_errors.StageNotFoundError(
@@ -376,3 +402,9 @@ class SFStageFileSystem(fsspec.AbstractFileSystem):
376
402
  original_exception=fileset_errors.FileSetError(str(e)),
377
403
  )
378
404
  return presigned_urls
405
+
406
+
407
+ def _match_error_code(ex: snowpark_exceptions.SnowparkSQLException, error_code: int) -> bool:
408
+ # Snowpark writes error code to message instead of populating e.error_code
409
+ error_code_str = str(error_code)
410
+ return ex.error_code == error_code_str or error_code_str in ex.message
@@ -1,6 +1,6 @@
1
1
  from snowflake.ml.model._client.model.model_impl import Model
2
- from snowflake.ml.model._client.model.model_version_impl import ModelVersion
2
+ from snowflake.ml.model._client.model.model_version_impl import ExportMode, ModelVersion
3
3
  from snowflake.ml.model.models.huggingface_pipeline import HuggingFacePipelineModel
4
4
  from snowflake.ml.model.models.llm import LLM, LLMOptions
5
5
 
6
- __all__ = ["Model", "ModelVersion", "HuggingFacePipelineModel", "LLM", "LLMOptions"]
6
+ __all__ = ["Model", "ModelVersion", "ExportMode", "HuggingFacePipelineModel", "LLM", "LLMOptions"]
@@ -2,6 +2,7 @@ from types import ModuleType
2
2
  from typing import Any, Dict, List, Literal, Optional, Union, cast, overload
3
3
 
4
4
  import pandas as pd
5
+ from typing_extensions import deprecated
5
6
 
6
7
  from snowflake.ml._internal.exceptions import (
7
8
  error_codes,
@@ -23,6 +24,7 @@ from snowflake.ml.model._signatures import snowpark_handler
23
24
  from snowflake.snowpark import DataFrame as SnowparkDataFrame, Session, functions as F
24
25
 
25
26
 
27
+ @deprecated("Only used by PrPr model registry.")
26
28
  @overload
27
29
  def save_model(
28
30
  *,
@@ -61,6 +63,7 @@ def save_model(
61
63
  ...
62
64
 
63
65
 
66
+ @deprecated("Only used by PrPr model registry.")
64
67
  @overload
65
68
  def save_model(
66
69
  *,
@@ -101,6 +104,7 @@ def save_model(
101
104
  ...
102
105
 
103
106
 
107
+ @deprecated("Only used by PrPr model registry.")
104
108
  @overload
105
109
  def save_model(
106
110
  *,
@@ -142,6 +146,7 @@ def save_model(
142
146
  ...
143
147
 
144
148
 
149
+ @deprecated("Only used by PrPr model registry.")
145
150
  def save_model(
146
151
  *,
147
152
  name: str,
@@ -208,6 +213,7 @@ def save_model(
208
213
  return m
209
214
 
210
215
 
216
+ @deprecated("Only used by PrPr model registry.")
211
217
  @overload
212
218
  def load_model(*, session: Session, stage_path: str) -> model_composer.ModelComposer:
213
219
  """Load the model into memory from a zip file in the stage.
@@ -219,6 +225,7 @@ def load_model(*, session: Session, stage_path: str) -> model_composer.ModelComp
219
225
  ...
220
226
 
221
227
 
228
+ @deprecated("Only used by PrPr model registry.")
222
229
  @overload
223
230
  def load_model(*, session: Session, stage_path: str, meta_only: Literal[False]) -> model_composer.ModelComposer:
224
231
  """Load the model into memory from a zip file in the stage.
@@ -231,6 +238,7 @@ def load_model(*, session: Session, stage_path: str, meta_only: Literal[False])
231
238
  ...
232
239
 
233
240
 
241
+ @deprecated("Only used by PrPr model registry.")
234
242
  @overload
235
243
  def load_model(*, session: Session, stage_path: str, meta_only: Literal[True]) -> model_composer.ModelComposer:
236
244
  """Load the model into memory from a zip file in the stage with metadata only.
@@ -243,6 +251,7 @@ def load_model(*, session: Session, stage_path: str, meta_only: Literal[True]) -
243
251
  ...
244
252
 
245
253
 
254
+ @deprecated("Only used by PrPr model registry.")
246
255
  def load_model(
247
256
  *,
248
257
  session: Session,
@@ -261,10 +270,11 @@ def load_model(
261
270
  Loaded model.
262
271
  """
263
272
  m = model_composer.ModelComposer(session=session, stage_path=stage_path)
264
- m.load(meta_only=meta_only)
273
+ m.legacy_load(meta_only=meta_only)
265
274
  return m
266
275
 
267
276
 
277
+ @deprecated("Only used by PrPr model registry.")
268
278
  @overload
269
279
  def deploy(
270
280
  session: Session,
@@ -290,6 +300,7 @@ def deploy(
290
300
  ...
291
301
 
292
302
 
303
+ @deprecated("Only used by PrPr model registry.")
293
304
  @overload
294
305
  def deploy(
295
306
  session: Session,
@@ -319,6 +330,7 @@ def deploy(
319
330
  ...
320
331
 
321
332
 
333
+ @deprecated("Only used by PrPr model registry.")
322
334
  def deploy(
323
335
  session: Session,
324
336
  *,
@@ -423,6 +435,7 @@ def deploy(
423
435
  return info
424
436
 
425
437
 
438
+ @deprecated("Only used by PrPr model registry.")
426
439
  @overload
427
440
  def predict(
428
441
  session: Session,
@@ -443,6 +456,7 @@ def predict(
443
456
  ...
444
457
 
445
458
 
459
+ @deprecated("Only used by PrPr model registry.")
446
460
  @overload
447
461
  def predict(
448
462
  session: Session,
@@ -462,6 +476,7 @@ def predict(
462
476
  ...
463
477
 
464
478
 
479
+ @deprecated("Only used by PrPr model registry.")
465
480
  def predict(
466
481
  session: Session,
467
482
  *,
@@ -350,3 +350,30 @@ class Model:
350
350
  tag_name=tag_name_id,
351
351
  statement_params=statement_params,
352
352
  )
353
+
354
+ @telemetry.send_api_usage_telemetry(
355
+ project=_TELEMETRY_PROJECT,
356
+ subproject=_TELEMETRY_SUBPROJECT,
357
+ )
358
+ def rename(self, model_name: str) -> None:
359
+ """Rename a model. Can be used to move a model when a fully qualified name is provided.
360
+
361
+ Args:
362
+ model_name: The new model name.
363
+ """
364
+ statement_params = telemetry.get_statement_params(
365
+ project=_TELEMETRY_PROJECT,
366
+ subproject=_TELEMETRY_SUBPROJECT,
367
+ )
368
+ db, schema, model, _ = identifier.parse_schema_level_object_identifier(model_name)
369
+ new_model_db = sql_identifier.SqlIdentifier(db) if db else None
370
+ new_model_schema = sql_identifier.SqlIdentifier(schema) if schema else None
371
+ new_model_id = sql_identifier.SqlIdentifier(model)
372
+ self._model_ops.rename(
373
+ model_name=self._model_name,
374
+ new_model_db=new_model_db,
375
+ new_model_schema=new_model_schema,
376
+ new_model_name=new_model_id,
377
+ statement_params=statement_params,
378
+ )
379
+ self._model_name = new_model_id
@@ -1,20 +1,29 @@
1
- import re
1
+ import enum
2
+ import pathlib
3
+ import tempfile
4
+ import warnings
2
5
  from typing import Any, Callable, Dict, List, Optional, Union
3
6
 
4
7
  import pandas as pd
5
8
 
6
- from snowflake import connector
7
9
  from snowflake.ml._internal import telemetry
8
10
  from snowflake.ml._internal.utils import sql_identifier
9
- from snowflake.ml.model import model_signature
11
+ from snowflake.ml.model import type_hints as model_types
10
12
  from snowflake.ml.model._client.ops import metadata_ops, model_ops
13
+ from snowflake.ml.model._model_composer import model_composer
11
14
  from snowflake.ml.model._model_composer.model_manifest import model_manifest_schema
15
+ from snowflake.ml.model._packager.model_handlers import snowmlmodel
12
16
  from snowflake.snowpark import dataframe
13
17
 
14
18
  _TELEMETRY_PROJECT = "MLOps"
15
19
  _TELEMETRY_SUBPROJECT = "ModelManagement"
16
20
 
17
21
 
22
+ class ExportMode(enum.Enum):
23
+ MODEL = "model"
24
+ FULL = "full"
25
+
26
+
18
27
  class ModelVersion:
19
28
  """Model Version Object representing a specific version of the model that could be run."""
20
29
 
@@ -207,61 +216,16 @@ class ModelVersion:
207
216
  statement_params=statement_params,
208
217
  )
209
218
 
210
- # Only used when the model does not contains user_data with client SDK information.
211
- def _legacy_show_functions(self) -> List[model_manifest_schema.ModelFunctionInfo]:
219
+ def _get_functions(self) -> List[model_manifest_schema.ModelFunctionInfo]:
212
220
  statement_params = telemetry.get_statement_params(
213
221
  project=_TELEMETRY_PROJECT,
214
222
  subproject=_TELEMETRY_SUBPROJECT,
215
223
  )
216
- manifest = self._model_ops.get_model_version_manifest(
217
- model_name=self._model_name,
218
- version_name=self._version_name,
219
- statement_params=statement_params,
220
- )
221
- model_meta = self._model_ops.get_model_version_native_packing_meta(
224
+ return self._model_ops.get_functions(
222
225
  model_name=self._model_name,
223
226
  version_name=self._version_name,
224
227
  statement_params=statement_params,
225
228
  )
226
- return_functions_info: List[model_manifest_schema.ModelFunctionInfo] = []
227
- for method in manifest["methods"]:
228
- # Method's name is resolved so we need to use case_sensitive as True to get the user-facing identifier.
229
- method_name = sql_identifier.SqlIdentifier(method["name"], case_sensitive=True).identifier()
230
- # Method's handler is `functions.<target_method>.infer`
231
- assert re.match(
232
- r"^functions\.([^\d\W]\w*)\.infer$", method["handler"]
233
- ), f"Get unexpected handler name {method['handler']}"
234
- target_method = method["handler"].split(".")[1]
235
- signature_dict = model_meta["signatures"][target_method]
236
- fi = model_manifest_schema.ModelFunctionInfo(
237
- name=method_name,
238
- target_method=target_method,
239
- signature=model_signature.ModelSignature.from_dict(signature_dict),
240
- )
241
- return_functions_info.append(fi)
242
- return return_functions_info
243
-
244
- def _get_functions(self) -> List[model_manifest_schema.ModelFunctionInfo]:
245
- statement_params = telemetry.get_statement_params(
246
- project=_TELEMETRY_PROJECT,
247
- subproject=_TELEMETRY_SUBPROJECT,
248
- )
249
- try:
250
- client_data = self._model_ops.get_client_data_in_user_data(
251
- model_name=self._model_name,
252
- version_name=self._version_name,
253
- statement_params=statement_params,
254
- )
255
- return [
256
- model_manifest_schema.ModelFunctionInfo(
257
- name=fi["name"],
258
- target_method=fi["target_method"],
259
- signature=model_signature.ModelSignature.from_dict(fi["signature"]),
260
- )
261
- for fi in client_data["functions"]
262
- ]
263
- except (NotImplementedError, ValueError, connector.DataError):
264
- return self._legacy_show_functions()
265
229
 
266
230
  @telemetry.send_api_usage_telemetry(
267
231
  project=_TELEMETRY_PROJECT,
@@ -288,6 +252,7 @@ class ModelVersion:
288
252
  X: Union[pd.DataFrame, dataframe.DataFrame],
289
253
  *,
290
254
  function_name: Optional[str] = None,
255
+ partition_column: Optional[str] = None,
291
256
  strict_input_validation: bool = False,
292
257
  ) -> Union[pd.DataFrame, dataframe.DataFrame]:
293
258
  """Invoke a method in a model version object.
@@ -296,12 +261,14 @@ class ModelVersion:
296
261
  X: The input data, which could be a pandas DataFrame or Snowpark DataFrame.
297
262
  function_name: The function name to run. It is the name used to call a function in SQL.
298
263
  Defaults to None. It can only be None if there is only 1 method.
264
+ partition_column: The partition column name to partition by.
299
265
  strict_input_validation: Enable stricter validation for the input data. This will result value range based
300
266
  type validation to make sure your input data won't overflow when providing to the model.
301
267
 
302
268
  Raises:
303
269
  ValueError: When no method with the corresponding name is available.
304
270
  ValueError: When there are more than 1 target methods available in the model but no function name specified.
271
+ ValueError: When the partition column is not a valid Snowflake identifier.
305
272
 
306
273
  Returns:
307
274
  The prediction data. It would be the same type dataframe as your input.
@@ -311,6 +278,10 @@ class ModelVersion:
311
278
  subproject=_TELEMETRY_SUBPROJECT,
312
279
  )
313
280
 
281
+ if partition_column is not None:
282
+ # Partition column must be a valid identifier
283
+ partition_column = sql_identifier.SqlIdentifier(partition_column)
284
+
314
285
  functions: List[model_manifest_schema.ModelFunctionInfo] = self._functions
315
286
  if function_name:
316
287
  req_method_name = sql_identifier.SqlIdentifier(function_name).identifier()
@@ -335,10 +306,126 @@ class ModelVersion:
335
306
  target_function_info = functions[0]
336
307
  return self._model_ops.invoke_method(
337
308
  method_name=sql_identifier.SqlIdentifier(target_function_info["name"]),
309
+ method_function_type=target_function_info["target_method_function_type"],
338
310
  signature=target_function_info["signature"],
339
311
  X=X,
340
312
  model_name=self._model_name,
341
313
  version_name=self._version_name,
342
314
  strict_input_validation=strict_input_validation,
315
+ partition_column=partition_column,
316
+ statement_params=statement_params,
317
+ )
318
+
319
+ @telemetry.send_api_usage_telemetry(
320
+ project=_TELEMETRY_PROJECT, subproject=_TELEMETRY_SUBPROJECT, func_params_to_log=["export_mode"]
321
+ )
322
+ def export(self, target_path: str, *, export_mode: ExportMode = ExportMode.MODEL) -> None:
323
+ """Export model files to a local directory.
324
+
325
+ Args:
326
+ target_path: Path to a local directory to export files to. A directory will be created if does not exist.
327
+ export_mode: The mode to export the model. Defaults to ExportMode.MODEL.
328
+ ExportMode.MODEL: All model files including environment to load the model and model weights.
329
+ ExportMode.FULL: Additional files to run the model in Warehouse, besides all files in MODEL mode,
330
+
331
+ Raises:
332
+ ValueError: Raised when the target path is a file or an non-empty folder.
333
+ """
334
+ target_local_path = pathlib.Path(target_path)
335
+ if target_local_path.is_file() or any(target_local_path.iterdir()):
336
+ raise ValueError(f"Target path {target_local_path} is a file or an non-empty folder.")
337
+
338
+ target_local_path.mkdir(parents=False, exist_ok=True)
339
+ statement_params = telemetry.get_statement_params(
340
+ project=_TELEMETRY_PROJECT,
341
+ subproject=_TELEMETRY_SUBPROJECT,
342
+ )
343
+ self._model_ops.download_files(
344
+ model_name=self._model_name,
345
+ version_name=self._version_name,
346
+ target_path=target_local_path,
347
+ mode=export_mode.value,
343
348
  statement_params=statement_params,
344
349
  )
350
+
351
+ @telemetry.send_api_usage_telemetry(
352
+ project=_TELEMETRY_PROJECT, subproject=_TELEMETRY_SUBPROJECT, func_params_to_log=["force", "options"]
353
+ )
354
+ def load(
355
+ self,
356
+ *,
357
+ force: bool = False,
358
+ options: Optional[model_types.ModelLoadOption] = None,
359
+ ) -> model_types.SupportedModelType:
360
+ """Load the underlying original Python object back from a model.
361
+ This operation requires to have the exact the same environment as the one when logging the model, otherwise,
362
+ the model might be not functional or some other problems might occur.
363
+
364
+ Args:
365
+ force: Bypass the best-effort environment validation. Defaults to False.
366
+ options: Options to specify when loading the model, check `snowflake.ml.model.type_hints` for available
367
+ options. Defaults to None.
368
+
369
+ Raises:
370
+ ValueError: Raised when the best-effort environment validation fails.
371
+
372
+ Returns:
373
+ The original Python object loaded from the model object.
374
+ """
375
+ statement_params = telemetry.get_statement_params(
376
+ project=_TELEMETRY_PROJECT,
377
+ subproject=_TELEMETRY_SUBPROJECT,
378
+ )
379
+ if not force:
380
+ with tempfile.TemporaryDirectory() as tmp_workspace_for_validation:
381
+ ws_path_for_validation = pathlib.Path(tmp_workspace_for_validation)
382
+ self._model_ops.download_files(
383
+ model_name=self._model_name,
384
+ version_name=self._version_name,
385
+ target_path=ws_path_for_validation,
386
+ mode="minimal",
387
+ statement_params=statement_params,
388
+ )
389
+ pk_for_validation = model_composer.ModelComposer.load(
390
+ ws_path_for_validation, meta_only=True, options=options
391
+ )
392
+ assert pk_for_validation.meta, (
393
+ "Unable to load model metadata for validation. "
394
+ f"model_name={self._model_name}, version_name={self._version_name}"
395
+ )
396
+
397
+ validation_errors = pk_for_validation.meta.env.validate_with_local_env(
398
+ check_snowpark_ml_version=(
399
+ pk_for_validation.meta.model_type == snowmlmodel.SnowMLModelHandler.HANDLER_TYPE
400
+ )
401
+ )
402
+ if validation_errors:
403
+ raise ValueError(
404
+ f"Unable to load this model due to following validation errors: {validation_errors}. "
405
+ "Make sure your local environment is the same as that when you logged the model, "
406
+ "or if you believe it should work, specify `force=True` to bypass this check."
407
+ )
408
+
409
+ warnings.warn(
410
+ "Loading model requires to have the exact the same environment as the one when "
411
+ "logging the model, otherwise, the model might be not functional or "
412
+ "some other problems might occur.",
413
+ category=RuntimeWarning,
414
+ stacklevel=2,
415
+ )
416
+
417
+ # We need the folder to be existed.
418
+ workspace = pathlib.Path(tempfile.mkdtemp())
419
+ self._model_ops.download_files(
420
+ model_name=self._model_name,
421
+ version_name=self._version_name,
422
+ target_path=workspace,
423
+ mode="model",
424
+ statement_params=statement_params,
425
+ )
426
+ pk = model_composer.ModelComposer.load(workspace, meta_only=False, options=options)
427
+ assert pk.model, (
428
+ "Unable to load model. "
429
+ f"model_name={self._model_name}, version_name={self._version_name}, metadata={pk.meta}"
430
+ )
431
+ return pk.model