snowflake-ml-python 2.4.0__py3-none-any.whl → 2.6.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 (98) hide show
  1. snowflake/cortex/_classify_text.py +38 -32
  2. snowflake/ml/_internal/env_utils.py +6 -2
  3. snowflake/ml/_internal/file_utils.py +18 -1
  4. snowflake/ml/_internal/platform_capabilities.py +1 -1
  5. snowflake/ml/dataset/dataset.py +1 -1
  6. snowflake/ml/experiment/_entities/run.py +61 -8
  7. snowflake/ml/experiment/experiment_tracking.py +8 -10
  8. snowflake/ml/feature_store/decl/__init__.py +168 -0
  9. snowflake/ml/feature_store/decl/api.py +1796 -0
  10. snowflake/ml/feature_store/decl/compiler.py +770 -0
  11. snowflake/ml/feature_store/decl/dependencies.py +163 -0
  12. snowflake/ml/feature_store/decl/enums.py +55 -0
  13. snowflake/ml/feature_store/decl/errors.py +87 -0
  14. snowflake/ml/feature_store/decl/exporter.py +2376 -0
  15. snowflake/ml/feature_store/decl/imperative_executor.py +3487 -0
  16. snowflake/ml/feature_store/decl/invariants.py +3869 -0
  17. snowflake/ml/feature_store/decl/loader.py +871 -0
  18. snowflake/ml/feature_store/decl/manifest.py +348 -0
  19. snowflake/ml/feature_store/decl/planner.py +1319 -0
  20. snowflake/ml/feature_store/decl/project_paths.py +152 -0
  21. snowflake/ml/feature_store/decl/python_codegen.py +413 -0
  22. snowflake/ml/feature_store/decl/queries.py +172 -0
  23. snowflake/ml/feature_store/decl/serializer.py +313 -0
  24. snowflake/ml/feature_store/decl/service.py +736 -0
  25. snowflake/ml/feature_store/decl/spec_compiler.py +612 -0
  26. snowflake/ml/feature_store/decl/spec_models.py +1040 -0
  27. snowflake/ml/feature_store/decl/state.py +1995 -0
  28. snowflake/ml/feature_store/decl/templating.py +158 -0
  29. snowflake/ml/feature_store/decl/types.py +219 -0
  30. snowflake/ml/feature_store/decl/udf_loader.py +99 -0
  31. snowflake/ml/feature_store/feature_store.py +45 -21
  32. snowflake/ml/feature_store/feature_view.py +59 -17
  33. snowflake/ml/feature_store/spec/table_schema_evolution.py +10 -4
  34. snowflake/ml/jobs/__init__.py +10 -0
  35. snowflake/ml/jobs/_interop/data_utils.py +34 -2
  36. snowflake/ml/jobs/_interop/legacy.py +3 -3
  37. snowflake/ml/jobs/_utils/constants.py +9 -0
  38. snowflake/ml/jobs/_utils/object_naming.py +45 -0
  39. snowflake/ml/jobs/_utils/option_parsing.py +102 -0
  40. snowflake/ml/jobs/_utils/runtime_env_utils.py +25 -1
  41. snowflake/ml/jobs/_utils/stage_utils.py +25 -1
  42. snowflake/ml/jobs/code_bundle.py +532 -0
  43. snowflake/ml/jobs/job.py +59 -12
  44. snowflake/ml/jobs/job_definition.py +20 -51
  45. snowflake/ml/jobs/manager.py +3 -1
  46. snowflake/ml/lineage/lineage_node.py +9 -1
  47. snowflake/ml/model/__init__.py +0 -2
  48. snowflake/ml/model/_client/model/batch_inference_task.py +5 -9
  49. snowflake/ml/model/_client/model/model_version_impl.py +24 -51
  50. snowflake/ml/model/_client/ops/model_ops.py +12 -19
  51. snowflake/ml/model/_client/ops/service_ops.py +3 -2
  52. snowflake/ml/model/_client/service/model_deployment_spec.py +53 -33
  53. snowflake/ml/model/_client/sql/model.py +17 -51
  54. snowflake/ml/model/_packager/model_handlers/huggingface/_handler.py +19 -50
  55. snowflake/ml/model/_packager/model_handlers/mlflow.py +66 -101
  56. snowflake/ml/model/_packager/model_meta/model_meta.py +3 -1
  57. snowflake/ml/model/_packager/model_runtime/_snowml_inference_alternative_requirements.py +2 -2
  58. snowflake/ml/model/_packager/model_runtime/model_runtime.py +5 -1
  59. snowflake/ml/model/models/huggingface.py +135 -37
  60. snowflake/ml/model/type_hints.py +3 -4
  61. snowflake/ml/modeling/_internal/optional_dependency.py +6 -30
  62. snowflake/ml/modeling/calibration/__init__.py +1 -2
  63. snowflake/ml/modeling/cluster/__init__.py +1 -2
  64. snowflake/ml/modeling/compose/__init__.py +1 -2
  65. snowflake/ml/modeling/covariance/__init__.py +1 -2
  66. snowflake/ml/modeling/decomposition/__init__.py +1 -2
  67. snowflake/ml/modeling/discriminant_analysis/__init__.py +1 -2
  68. snowflake/ml/modeling/ensemble/__init__.py +1 -2
  69. snowflake/ml/modeling/feature_selection/__init__.py +1 -2
  70. snowflake/ml/modeling/gaussian_process/__init__.py +1 -2
  71. snowflake/ml/modeling/impute/__init__.py +1 -2
  72. snowflake/ml/modeling/kernel_approximation/__init__.py +1 -2
  73. snowflake/ml/modeling/kernel_ridge/__init__.py +1 -2
  74. snowflake/ml/modeling/lightgbm/__init__.py +1 -2
  75. snowflake/ml/modeling/linear_model/__init__.py +1 -2
  76. snowflake/ml/modeling/manifold/__init__.py +1 -2
  77. snowflake/ml/modeling/metrics/__init__.py +2 -3
  78. snowflake/ml/modeling/mixture/__init__.py +1 -2
  79. snowflake/ml/modeling/model_selection/__init__.py +1 -2
  80. snowflake/ml/modeling/multiclass/__init__.py +1 -2
  81. snowflake/ml/modeling/naive_bayes/__init__.py +1 -2
  82. snowflake/ml/modeling/neighbors/__init__.py +1 -2
  83. snowflake/ml/modeling/neural_network/__init__.py +1 -2
  84. snowflake/ml/modeling/pipeline/__init__.py +1 -2
  85. snowflake/ml/modeling/preprocessing/__init__.py +1 -2
  86. snowflake/ml/modeling/semi_supervised/__init__.py +1 -2
  87. snowflake/ml/modeling/svm/__init__.py +1 -2
  88. snowflake/ml/modeling/tree/__init__.py +1 -2
  89. snowflake/ml/modeling/xgboost/__init__.py +1 -2
  90. snowflake/ml/registry/_manager/model_manager.py +0 -1
  91. snowflake/ml/registry/_manager/model_parameter_reconciler.py +31 -1
  92. snowflake/ml/version.py +1 -1
  93. {snowflake_ml_python-2.4.0.dist-info → snowflake_ml_python-2.6.0.dist-info}/METADATA +65 -4
  94. {snowflake_ml_python-2.4.0.dist-info → snowflake_ml_python-2.6.0.dist-info}/RECORD +97 -72
  95. snowflake/ml/model/models/huggingface_pipeline.py +0 -268
  96. {snowflake_ml_python-2.4.0.dist-info → snowflake_ml_python-2.6.0.dist-info}/WHEEL +0 -0
  97. {snowflake_ml_python-2.4.0.dist-info → snowflake_ml_python-2.6.0.dist-info}/licenses/LICENSE.txt +0 -0
  98. {snowflake_ml_python-2.4.0.dist-info → snowflake_ml_python-2.6.0.dist-info}/top_level.txt +0 -0
@@ -6,24 +6,23 @@ from typing_extensions import deprecated
6
6
  from snowflake import snowpark
7
7
  from snowflake.cortex._util import (
8
8
  CORTEX_FUNCTIONS_TELEMETRY_PROJECT,
9
- call_sql_function,
9
+ SnowflakeAuthenticationException,
10
10
  warn_cortex_deprecated,
11
11
  )
12
12
  from snowflake.ml._internal import telemetry
13
- from snowflake.snowpark import functions
13
+ from snowflake.snowpark import context, functions
14
14
 
15
15
  _AI_CLASSIFY_FUNCTION_NAME = "AI_CLASSIFY"
16
- # Legacy CLASSIFY_TEXT always returned exactly one label. AI_CLASSIFY defaults to single-label mode, but
17
- # we set output_mode explicitly so the single-label contract can't drift and multi-label results can
18
- # never leak through.
19
- _AI_CLASSIFY_SINGLE_LABEL_CONFIG = {"output_mode": "single"}
16
+ # AI_CLASSIFY requires its config argument to be a constant object literal. A Python dict is rendered by
17
+ # Snowpark as PARSE_JSON('...')::OBJECT, which the server rejects ("... is not a constant"), so emit the
18
+ # config as a SQL object constant via sql_expr -- this mirrors snowflake.snowpark.functions.ai_classify.
19
+ # Legacy CLASSIFY_TEXT was always single-label, so set output_mode explicitly to keep that contract.
20
+ _AI_CLASSIFY_SINGLE_LABEL_CONFIG_SQL = "{'output_mode': 'single'}"
20
21
 
21
22
 
22
23
  def _adapt_ai_classify_result(result: Any) -> str:
23
24
  """Map an AI_CLASSIFY result to the legacy CLASSIFY_TEXT {"label": ...} JSON string."""
24
- # Legacy classify_text returned the raw CLASSIFY_TEXT OBJECT, which the immediate (non-Column) path
25
- # collects as a JSON string such as '{"label": "positive"}'. We reproduce that exact shape so
26
- # existing callers that json.loads the result and read ["label"] keep working.
25
+ # Used for non-Column results (e.g. a dict/JSON string): reproduce the legacy single-label object shape.
27
26
  parsed: Any = result
28
27
  if isinstance(result, str):
29
28
  try:
@@ -40,6 +39,20 @@ def _adapt_ai_classify_result(result: Any) -> str:
40
39
  return json.dumps({"label": label})
41
40
 
42
41
 
42
+ def _ai_classify_label_column(
43
+ str_input: str | snowpark.Column,
44
+ categories: list[str] | snowpark.Column,
45
+ ) -> snowpark.Column:
46
+ """Call AI_CLASSIFY in single-label mode and re-wrap to the legacy CLASSIFY_TEXT {"label": ...} OBJECT."""
47
+ result = functions.builtin(_AI_CLASSIFY_FUNCTION_NAME)(
48
+ str_input, categories, functions.sql_expr(_AI_CLASSIFY_SINGLE_LABEL_CONFIG_SQL)
49
+ )
50
+ # AI_CLASSIFY returns {"labels": [...]}; collapse to the legacy single {"label": ...}. Subscript access
51
+ # (not functions.get with a bare string, which Snowpark treats as a column identifier) uses literal keys.
52
+ label = functions.coalesce(result["labels"][0], result["label"])
53
+ return functions.object_construct(functions.lit("label"), label)
54
+
55
+
43
56
  @telemetry.send_api_usage_telemetry(
44
57
  project=CORTEX_FUNCTIONS_TELEMETRY_PROJECT,
45
58
  )
@@ -56,32 +69,25 @@ def classify_text(
56
69
  session: The snowpark session to use. Will be inferred by context if not specified.
57
70
 
58
71
  Returns:
59
- A column of classification responses.
72
+ A column of classification responses (legacy CLASSIFY_TEXT {"label": ...} shape).
73
+
74
+ Raises:
75
+ SnowflakeAuthenticationException: if no session is provided and none is active.
60
76
  """
61
77
  warn_cortex_deprecated("classify_text", "ai_classify")
62
- result = _classify_text_impl(
63
- _AI_CLASSIFY_FUNCTION_NAME, str_input, categories, _AI_CLASSIFY_SINGLE_LABEL_CONFIG, session=session
64
- )
65
- if isinstance(result, snowpark.Column):
66
- # AI_CLASSIFY returns {"labels": [...]}; re-wrap as the legacy CLASSIFY_TEXT {"label": ...} OBJECT
67
- # so downstream SQL that reads col["label"] is unchanged. Subscript access (not functions.get with
68
- # a bare string, which Snowpark treats as a column identifier) extracts the field by literal key.
69
- label = functions.coalesce(result["labels"][0], result["label"])
70
- return functions.object_construct(functions.lit("label"), label)
71
- return _adapt_ai_classify_result(result)
72
-
78
+ column = _ai_classify_label_column(str_input, categories)
79
+ if isinstance(str_input, snowpark.Column) or isinstance(categories, snowpark.Column):
80
+ return column
73
81
 
74
- def _classify_text_impl(
75
- function: str,
76
- str_input: str | snowpark.Column,
77
- categories: list[str] | snowpark.Column,
78
- config: dict[str, Any] | None = None,
79
- session: snowpark.Session | None = None,
80
- ) -> str | snowpark.Column:
81
- args: list[Any] = [str_input, categories]
82
- if config is not None:
83
- args.append(config)
84
- return cast(str | snowpark.Column, call_sql_function(function, session, *args))
82
+ # Immediate (literal) path: evaluate and return the collected OBJECT as a JSON string, exactly as the
83
+ # legacy CLASSIFY_TEXT immediate path did.
84
+ session = session or context.get_active_session()
85
+ if session is None:
86
+ raise SnowflakeAuthenticationException(
87
+ """Session required. Provide the session through a session=... argument or ensure an active session is
88
+ available in your environment."""
89
+ )
90
+ return cast(str, session.create_dataframe([snowpark.Row()]).select(column).collect()[0][0])
85
91
 
86
92
 
87
93
  ClassifyText = deprecated(
@@ -90,6 +90,9 @@ def _validate_pip_requirement_string(req_str: str) -> requirements.Requirement:
90
90
  Returns:
91
91
  A requirements.Requirement object containing the requirement information.
92
92
  """
93
+ # A requirement string must not carry surrounding whitespace: packaging>=26 accepts only a
94
+ # requirement that ends at the end of the string, so a trailing newline is a parse error.
95
+ req_str = req_str.strip()
93
96
  try:
94
97
  r = requirements.Requirement(req_str)
95
98
 
@@ -780,8 +783,9 @@ def load_requirements_file(path: pathlib.Path) -> list[requirements.Requirement]
780
783
  with open(path, encoding="utf-8") as f:
781
784
  reqs = f.readlines()
782
785
 
783
- # Filter out pip options
784
- reqs = [line for line in reqs if line.strip() and not line.strip().startswith(("-", "#"))]
786
+ # "-" lines are pip options (e.g. --extra-index-url) and "#" lines are comments; neither is a
787
+ # requirement. Strip as well, since a requirement string must not keep readlines()' newline.
788
+ reqs = [stripped for line in reqs if (stripped := line.strip()) and not stripped.startswith(("-", "#"))]
785
789
 
786
790
  return validate_pip_requirement_string_list(reqs)
787
791
 
@@ -120,7 +120,21 @@ def make_archive(
120
120
  )
121
121
 
122
122
 
123
- def zip_python_package(zipfile_path: str, package_name: str, ignore_generated_py_file: bool = True) -> None:
123
+ def zip_python_package(
124
+ zipfile_path: str,
125
+ package_name: str,
126
+ ignore_generated_py_file: bool = True,
127
+ *,
128
+ exclude_dir_names: tuple[str, ...] = (),
129
+ ) -> None:
130
+ """Zip an imported Python package.
131
+
132
+ Args:
133
+ zipfile_path: Destination zip path.
134
+ package_name: Dotted package name to zip.
135
+ ignore_generated_py_file: When True, omit generated bytecode and stub files.
136
+ exclude_dir_names: Directory names to omit anywhere in the package. The directory entry itself is not written.
137
+ """
124
138
  import importlib_resources
125
139
  from importlib_resources import abc as importlib_resources_abc
126
140
 
@@ -131,6 +145,7 @@ def zip_python_package(zipfile_path: str, package_name: str, ignore_generated_py
131
145
 
132
146
  base_dirs = package_name.split(".")
133
147
  assert len(base_dirs) >= 1, "Invalid package name."
148
+ excluded_dirs = set(exclude_dir_names)
134
149
 
135
150
  with zipfile.ZipFile(zipfile_path, mode="w", compression=zipfile.ZIP_DEFLATED) as zf:
136
151
  for i in range(len(base_dirs)):
@@ -141,6 +156,8 @@ def zip_python_package(zipfile_path: str, package_name: str, ignore_generated_py
141
156
  def _add_to_zip(
142
157
  zf: zipfile.ZipFile, path_info: importlib_resources_abc.Traversable, base_arcname: pathlib.PurePosixPath
143
158
  ) -> None:
159
+ if path_info.name in excluded_dirs:
160
+ return
144
161
  if path_info.is_file():
145
162
  if ignore_generated_py_file and path_info.name.endswith(GENERATED_PY_FILE_EXT):
146
163
  return
@@ -93,7 +93,7 @@ class PlatformCapabilities:
93
93
  return self._get_bool_feature(ENABLE_MODEL_METHOD_SIGNATURE_PARAMETERS, False)
94
94
 
95
95
  def is_lora_adapters_enabled(self) -> bool:
96
- return False
96
+ return self._get_bool_feature(ENABLE_LORA_ADAPTERS, False)
97
97
 
98
98
  def is_single_output_native_type_enabled(self) -> bool:
99
99
  """Whether a single, non-OBJECT model FUNCTION output is registered with its native SQL type.
@@ -341,7 +341,7 @@ class Dataset(lineage_node.LineageNode):
341
341
  metadata = dataset_metadata.DatasetMetadata(
342
342
  source_query=source_query,
343
343
  owner=self._session.sql("SELECT CURRENT_USER()").collect(statement_params=_TELEMETRY_STATEMENT_PARAMS)[0][
344
- "CURRENT_USER()"
344
+ 0
345
345
  ],
346
346
  exclude_cols=exclude_cols,
347
347
  label_cols=label_cols,
@@ -2,9 +2,11 @@ import types
2
2
  import warnings
3
3
  from typing import TYPE_CHECKING
4
4
 
5
- from snowflake.ml._internal.utils import sql_identifier
5
+ from snowflake import snowpark
6
+ from snowflake.ml._internal.utils import identifier, sql_identifier
6
7
  from snowflake.ml.experiment import _experiment_info as experiment_info
7
8
  from snowflake.ml.experiment._entities import run_metadata
9
+ from snowflake.ml.lineage import lineage_node
8
10
 
9
11
  if TYPE_CHECKING:
10
12
  from snowflake.ml.experiment import experiment_tracking
@@ -12,13 +14,24 @@ if TYPE_CHECKING:
12
14
  METADATA_SIZE_WARNING_MESSAGE = "It is likely that no further metrics or parameters will be logged for this run."
13
15
 
14
16
 
15
- class Run:
17
+ class Run(lineage_node.LineageNode):
18
+ """An experiment run.
19
+
20
+ When created by ``ExperimentTracking.start_run``, the run is an active context manager that
21
+ patches model logging and ends the run on exit. When returned by the lineage system
22
+ (``model_version.lineage(direction="upstream", domain_filter={"experiment"})``), it is a
23
+ read-only handle exposing the identifiers needed to look up metrics and parameters.
24
+ """
25
+
16
26
  def __init__(
17
27
  self,
18
- experiment_tracking: "experiment_tracking.ExperimentTracking",
28
+ experiment_tracking: "experiment_tracking.ExperimentTracking | None" = None,
19
29
  *,
20
30
  experiment_name: sql_identifier.SqlIdentifier,
21
31
  run_name: sql_identifier.SqlIdentifier,
32
+ session: snowpark.Session | None = None,
33
+ database_name: str | None = None,
34
+ schema_name: str | None = None,
22
35
  ) -> None:
23
36
  self._experiment_tracking = experiment_tracking
24
37
  self.experiment_name = experiment_name
@@ -27,10 +40,31 @@ class Run:
27
40
  # Whether we've already shown the user a warning about exceeding the run metadata size limit.
28
41
  self._warned_about_metadata_size = False
29
42
 
43
+ if experiment_tracking is not None:
44
+ _session = experiment_tracking._session
45
+ self.database_name = str(experiment_tracking._database_name)
46
+ self.schema_name = str(experiment_tracking._schema_name)
47
+ else:
48
+ if session is None or database_name is None or schema_name is None:
49
+ raise ValueError(
50
+ "session, database_name, and schema_name are required when experiment_tracking is None"
51
+ )
52
+ _session = session
53
+ self.database_name = database_name
54
+ self.schema_name = schema_name
55
+
30
56
  self._patcher = experiment_info.ExperimentInfoPatcher(
31
57
  experiment_info=self._get_experiment_info(),
32
58
  )
33
59
 
60
+ # A run is modelled in lineage as a version of its experiment, so the node name is the experiment's.
61
+ super().__init__(
62
+ session=_session,
63
+ name=self._fully_qualified_experiment_name(),
64
+ domain="experiment",
65
+ version=str(run_name),
66
+ )
67
+
34
68
  def __enter__(self) -> "Run":
35
69
  self._patcher.__enter__()
36
70
  return self
@@ -42,18 +76,19 @@ class Run:
42
76
  tb: types.TracebackType | None,
43
77
  ) -> None:
44
78
  self._patcher.__exit__(exc_type, exc_value, tb)
45
- if self._experiment_tracking._run is self:
79
+ if self._experiment_tracking is not None and self._experiment_tracking._run is self:
46
80
  if exc_type is not None:
47
81
  self._experiment_tracking._try_log_exception(exc_type, exc_value, tb)
48
82
  self._experiment_tracking.end_run(status=run_metadata.RunStatus.FAILED.value)
49
83
  else:
50
84
  self._experiment_tracking.end_run()
51
85
 
86
+ def _fully_qualified_experiment_name(self) -> str:
87
+ return sql_identifier.get_fully_qualified_name(self.database_name, self.schema_name, self.experiment_name)
88
+
52
89
  def _get_experiment_info(self) -> experiment_info.ExperimentInfo:
53
90
  return experiment_info.ExperimentInfo(
54
- fully_qualified_name=self._experiment_tracking._sql_client.fully_qualified_object_name(
55
- self._experiment_tracking._database_name, self._experiment_tracking._schema_name, self.experiment_name
56
- ),
91
+ fully_qualified_name=self._fully_qualified_experiment_name(),
57
92
  run_name=self.name.identifier(),
58
93
  )
59
94
 
@@ -67,9 +102,27 @@ class Run:
67
102
  RuntimeWarning: If the experiment tracking instance was created with warnings_as_errors=True.
68
103
  """
69
104
  message = f"{sql_error_msg}. {METADATA_SIZE_WARNING_MESSAGE}"
70
- if self._experiment_tracking._warnings_as_errors:
105
+ if self._experiment_tracking is not None and self._experiment_tracking._warnings_as_errors:
71
106
  raise RuntimeWarning(message)
72
107
  # Once the limit is hit every subsequent log attempt fails the same way, so warn only once.
73
108
  if not self._warned_about_metadata_size:
74
109
  warnings.warn(message, RuntimeWarning, stacklevel=2)
75
110
  self._warned_about_metadata_size = True
111
+
112
+ @staticmethod
113
+ def _load_from_lineage_node(
114
+ session: snowpark.Session,
115
+ name: str,
116
+ version: str,
117
+ ) -> "Run":
118
+ database_name, schema_name, experiment_name = identifier.parse_schema_level_object_identifier(name)
119
+ return Run(
120
+ experiment_name=sql_identifier.SqlIdentifier(experiment_name),
121
+ run_name=sql_identifier.SqlIdentifier(version),
122
+ session=session,
123
+ database_name=database_name,
124
+ schema_name=schema_name,
125
+ )
126
+
127
+
128
+ lineage_node.DOMAIN_LINEAGE_REGISTRY["experiment"] = Run
@@ -25,7 +25,6 @@ from snowflake.ml.experiment._client import (
25
25
  experiment_tracking_sql_client as sql_client,
26
26
  )
27
27
  from snowflake.ml.experiment._entities import run_metadata
28
- from snowflake.ml.lineage import lineage_node
29
28
  from snowflake.ml.model import type_hints
30
29
  from snowflake.ml.utils import sql_client as sql_client_utils
31
30
  from snowflake.snowpark import functions
@@ -328,15 +327,14 @@ class ExperimentTracking:
328
327
  else:
329
328
  raise RuntimeError("No run is active. Please provide a run_name or start a run.")
330
329
 
331
- experiment_fqn = self._sql_client.fully_qualified_object_name(
332
- self._database_name, self._schema_name, self._experiment.name
333
- )
334
- run_node = lineage_node.LineageNode(
335
- session=self._session,
336
- name=experiment_fqn,
337
- domain="experiment",
338
- version=resolved_run_name.identifier(),
339
- )
330
+ if self._run and self._run.name == resolved_run_name:
331
+ run_node = self._run
332
+ else:
333
+ run_node = entities.Run(
334
+ experiment_tracking=self,
335
+ experiment_name=self._experiment.name,
336
+ run_name=resolved_run_name,
337
+ )
340
338
  logged_models = run_node.lineage(direction="downstream", domain_filter={"model"})
341
339
  return [model for model in logged_models if isinstance(model, ml_model.ModelVersion)]
342
340
 
@@ -0,0 +1,168 @@
1
+ """Public API for the declarative feature store library.
2
+
3
+ Import the key functions and types from this package:
4
+
5
+ from snowflake.ml.feature_store.decl import (
6
+ load_specs,
7
+ validate_specs,
8
+ generate_plan,
9
+ fetch_applied_state,
10
+ SpecBatch,
11
+ AppliedState,
12
+ Plan,
13
+ PlanOptions,
14
+ ValidationResult,
15
+ PlanOp,
16
+ AppliedObject,
17
+ SpecLoadError,
18
+ ValidationError,
19
+ DependencyError,
20
+ StateDriftError,
21
+ FSBaseType,
22
+ FeatureViewKind,
23
+ SourceType,
24
+ FeatureAggregationMethod,
25
+ OpKind,
26
+ TYPE_ALIASES,
27
+ normalize_type,
28
+ FSColumn,
29
+ SpecBase,
30
+ Entity,
31
+ StreamingSource,
32
+ BatchSource,
33
+ SourceRef,
34
+ UDF,
35
+ Feature,
36
+ FeatureView,
37
+ FeatureViewRef,
38
+ FeatureGroup,
39
+ )
40
+ """
41
+
42
+ try:
43
+ from snowflake.ml.feature_store.decl.api import (
44
+ discover_project,
45
+ fetch_applied_state,
46
+ generate_plan,
47
+ load_manifest,
48
+ load_project,
49
+ load_specs,
50
+ resolve_datasource_columns,
51
+ resolve_target,
52
+ validate_specs,
53
+ )
54
+ except ModuleNotFoundError: # lower-layer BUILD targets omit api.py
55
+ pass
56
+ from snowflake.ml.feature_store.decl.enums import (
57
+ TYPE_ALIASES,
58
+ FeatureAggregationMethod,
59
+ FeatureViewKind,
60
+ FSBaseType,
61
+ OpKind,
62
+ SourceType,
63
+ normalize_type,
64
+ )
65
+ from snowflake.ml.feature_store.decl.errors import (
66
+ DependencyError,
67
+ SpecLoadError,
68
+ StateDriftError,
69
+ ValidationError,
70
+ )
71
+ from snowflake.ml.feature_store.decl.manifest import (
72
+ FSManifest,
73
+ FSTarget,
74
+ FSTemplating,
75
+ InvalidManifestError,
76
+ ManifestConfigurationError,
77
+ ManifestNotFoundError,
78
+ TargetContext,
79
+ )
80
+ from snowflake.ml.feature_store.decl.project_paths import FSProjectPaths
81
+ from snowflake.ml.feature_store.decl.spec_models import (
82
+ UDF,
83
+ Backfill,
84
+ BatchFeatureView,
85
+ BatchSource,
86
+ Entity,
87
+ Feature,
88
+ FeatureGroup,
89
+ FeatureView,
90
+ FeatureViewRef,
91
+ FSColumn,
92
+ RealtimeFeatureView,
93
+ SourceRef,
94
+ SpecBase,
95
+ StorageConfig,
96
+ StreamingFeatureView,
97
+ StreamingSource,
98
+ )
99
+ from snowflake.ml.feature_store.decl.types import (
100
+ AppliedObject,
101
+ AppliedState,
102
+ Plan,
103
+ PlanOp,
104
+ PlanOptions,
105
+ SpecBatch,
106
+ ValidationResult,
107
+ )
108
+
109
+ __all__ = [
110
+ # api.py
111
+ "load_specs",
112
+ "validate_specs",
113
+ "generate_plan",
114
+ "fetch_applied_state",
115
+ "resolve_datasource_columns",
116
+ "load_manifest",
117
+ "discover_project",
118
+ "resolve_target",
119
+ "load_project",
120
+ # enums.py
121
+ "FSBaseType",
122
+ "FeatureViewKind",
123
+ "SourceType",
124
+ "FeatureAggregationMethod",
125
+ "OpKind",
126
+ "TYPE_ALIASES",
127
+ "normalize_type",
128
+ # errors.py
129
+ "SpecLoadError",
130
+ "ValidationError",
131
+ "DependencyError",
132
+ "StateDriftError",
133
+ # manifest.py
134
+ "FSManifest",
135
+ "FSTarget",
136
+ "FSTemplating",
137
+ "TargetContext",
138
+ "ManifestNotFoundError",
139
+ "InvalidManifestError",
140
+ "ManifestConfigurationError",
141
+ # project_paths.py
142
+ "FSProjectPaths",
143
+ # spec_models.py
144
+ "FSColumn",
145
+ "SpecBase",
146
+ "Entity",
147
+ "StreamingSource",
148
+ "BatchSource",
149
+ "SourceRef",
150
+ "UDF",
151
+ "Feature",
152
+ "FeatureView",
153
+ "StreamingFeatureView",
154
+ "BatchFeatureView",
155
+ "RealtimeFeatureView",
156
+ "FeatureViewRef",
157
+ "FeatureGroup",
158
+ "Backfill",
159
+ "StorageConfig",
160
+ # types.py
161
+ "AppliedObject",
162
+ "AppliedState",
163
+ "PlanOp",
164
+ "Plan",
165
+ "ValidationResult",
166
+ "PlanOptions",
167
+ "SpecBatch",
168
+ ]