mlrun 1.7.0rc33__py3-none-any.whl → 1.7.0rc34__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.

Potentially problematic release.


This version of mlrun might be problematic. Click here for more details.

@@ -170,6 +170,7 @@ from .project import (
170
170
  Project,
171
171
  ProjectDesiredState,
172
172
  ProjectMetadata,
173
+ ProjectOut,
173
174
  ProjectOutput,
174
175
  ProjectOwner,
175
176
  ProjectsOutput,
@@ -38,3 +38,6 @@ class ImageBuilder(pydantic.BaseModel):
38
38
  build_pod: typing.Optional[str] = None
39
39
  requirements: typing.Optional[list] = None
40
40
  source_code_target_dir: typing.Optional[str] = None
41
+
42
+ class Config:
43
+ extra = pydantic.Extra.allow
@@ -119,6 +119,13 @@ class FunctionSpec(pydantic.BaseModel):
119
119
  service_account: typing.Optional[ServiceAccount]
120
120
  state_thresholds: typing.Optional[StateThresholds]
121
121
 
122
+ class Config:
123
+ extra = pydantic.Extra.allow
124
+
122
125
 
123
126
  class Function(pydantic.BaseModel):
124
127
  spec: typing.Optional[FunctionSpec]
128
+ application: typing.Optional[dict[str, typing.Any]]
129
+
130
+ class Config:
131
+ extra = pydantic.Extra.allow
@@ -100,6 +100,29 @@ class ProjectSpec(pydantic.BaseModel):
100
100
  extra = pydantic.Extra.allow
101
101
 
102
102
 
103
+ class ProjectSpecOut(pydantic.BaseModel):
104
+ description: typing.Optional[str] = None
105
+ owner: typing.Optional[str] = None
106
+ goals: typing.Optional[str] = None
107
+ params: typing.Optional[dict] = {}
108
+ functions: typing.Optional[list] = []
109
+ workflows: typing.Optional[list] = []
110
+ artifacts: typing.Optional[list] = []
111
+ artifact_path: typing.Optional[str] = None
112
+ conda: typing.Optional[str] = None
113
+ source: typing.Optional[str] = None
114
+ subpath: typing.Optional[str] = None
115
+ origin_url: typing.Optional[str] = None
116
+ desired_state: typing.Optional[ProjectDesiredState] = ProjectDesiredState.online
117
+ custom_packagers: typing.Optional[list[tuple[str, bool]]] = None
118
+ default_image: typing.Optional[str] = None
119
+ build: typing.Any = None
120
+ default_function_node_selector: typing.Optional[dict] = {}
121
+
122
+ class Config:
123
+ extra = pydantic.Extra.allow
124
+
125
+
103
126
  class Project(pydantic.BaseModel):
104
127
  kind: ObjectKind = pydantic.Field(ObjectKind.project, const=True)
105
128
  metadata: ProjectMetadata
@@ -107,6 +130,15 @@ class Project(pydantic.BaseModel):
107
130
  status: ObjectStatus = ObjectStatus()
108
131
 
109
132
 
133
+ # The reason we have a different schema for the response model is that we don't want to validate project.spec.build in
134
+ # the response as the validation was added late and there may be corrupted values in the DB.
135
+ class ProjectOut(pydantic.BaseModel):
136
+ kind: ObjectKind = pydantic.Field(ObjectKind.project, const=True)
137
+ metadata: ProjectMetadata
138
+ spec: ProjectSpecOut = ProjectSpecOut()
139
+ status: ObjectStatus = ObjectStatus()
140
+
141
+
110
142
  class ProjectOwner(pydantic.BaseModel):
111
143
  username: str
112
144
  access_key: str
@@ -134,16 +166,16 @@ class IguazioProject(pydantic.BaseModel):
134
166
 
135
167
 
136
168
  # The format query param controls the project type used:
137
- # full - Project
169
+ # full - ProjectOut
138
170
  # name_only - str
139
171
  # summary - ProjectSummary
140
172
  # leader - currently only IguazioProject supported
141
173
  # The way pydantic handles typing.Union is that it takes the object and tries to coerce it to be the types of the
142
- # union by the definition order. Therefore we can't currently add generic dict for all leader formats, but we need
174
+ # union by the definition order. Therefore, we can't currently add generic dict for all leader formats, but we need
143
175
  # to add a specific classes for them. it's frustrating but couldn't find other workaround, see:
144
176
  # https://github.com/samuelcolvin/pydantic/issues/1423, https://github.com/samuelcolvin/pydantic/issues/619
145
177
  ProjectOutput = typing.TypeVar(
146
- "ProjectOutput", Project, str, ProjectSummary, IguazioProject
178
+ "ProjectOutput", ProjectOut, str, ProjectSummary, IguazioProject
147
179
  )
148
180
 
149
181
 
mlrun/db/base.py CHANGED
@@ -690,8 +690,11 @@ class RunDBInterface(ABC):
690
690
  @abstractmethod
691
691
  def store_api_gateway(
692
692
  self,
693
- api_gateway: mlrun.common.schemas.APIGateway,
694
- project: str = None,
693
+ api_gateway: Union[
694
+ mlrun.common.schemas.APIGateway,
695
+ "mlrun.runtimes.nuclio.api_gateway.APIGateway",
696
+ ],
697
+ project: Optional[str] = None,
695
698
  ):
696
699
  pass
697
700
 
mlrun/db/httpdb.py CHANGED
@@ -1015,7 +1015,7 @@ class HTTPRunDB(RunDBInterface):
1015
1015
  "format": format_,
1016
1016
  "tag": tag,
1017
1017
  "tree": tree,
1018
- "uid": uid,
1018
+ "object_uid": uid,
1019
1019
  }
1020
1020
  if iter is not None:
1021
1021
  params["iter"] = str(iter)
@@ -1051,7 +1051,7 @@ class HTTPRunDB(RunDBInterface):
1051
1051
  "key": key,
1052
1052
  "tag": tag,
1053
1053
  "tree": tree,
1054
- "uid": uid,
1054
+ "object_uid": uid,
1055
1055
  "iter": iter,
1056
1056
  "deletion_strategy": deletion_strategy,
1057
1057
  }
@@ -1071,8 +1071,8 @@ class HTTPRunDB(RunDBInterface):
1071
1071
  project=None,
1072
1072
  tag=None,
1073
1073
  labels: Optional[Union[dict[str, str], list[str]]] = None,
1074
- since=None,
1075
- until=None,
1074
+ since: Optional[datetime] = None,
1075
+ until: Optional[datetime] = None,
1076
1076
  iter: int = None,
1077
1077
  best_iteration: bool = False,
1078
1078
  kind: str = None,
@@ -1102,8 +1102,8 @@ class HTTPRunDB(RunDBInterface):
1102
1102
  :param tag: Return artifacts assigned this tag.
1103
1103
  :param labels: Return artifacts that have these labels. Labels can either be a dictionary {"label": "value"} or
1104
1104
  a list of "label=value" (match label key and value) or "label" (match just label key) strings.
1105
- :param since: Not in use in :py:class:`HTTPRunDB`.
1106
- :param until: Not in use in :py:class:`HTTPRunDB`.
1105
+ :param since: Return artifacts updated after this date (as datetime object).
1106
+ :param until: Return artifacts updated before this date (as datetime object).
1107
1107
  :param iter: Return artifacts from a specific iteration (where ``iter=0`` means the root iteration). If
1108
1108
  ``None`` (default) return artifacts from all iterations.
1109
1109
  :param best_iteration: Returns the artifact which belongs to the best iteration of a given run, in the case of
@@ -1137,6 +1137,8 @@ class HTTPRunDB(RunDBInterface):
1137
1137
  "format": format_,
1138
1138
  "producer_uri": producer_uri,
1139
1139
  "limit": limit,
1140
+ "since": datetime_to_iso(since),
1141
+ "until": datetime_to_iso(until),
1140
1142
  }
1141
1143
  error = "list artifacts"
1142
1144
  endpoint_path = f"projects/{project}/artifacts"
@@ -1684,7 +1686,7 @@ class HTTPRunDB(RunDBInterface):
1684
1686
  last_log_timestamp = float(
1685
1687
  resp.headers.get("x-mlrun-last-timestamp", "0.0")
1686
1688
  )
1687
- if func.kind in mlrun.runtimes.RuntimeKinds.nuclio_runtimes():
1689
+ if func.kind in mlrun.runtimes.RuntimeKinds.pure_nuclio_deployed_runtimes():
1688
1690
  mlrun.runtimes.nuclio.function.enrich_nuclio_function_from_headers(
1689
1691
  func, resp.headers
1690
1692
  )
mlrun/execution.py CHANGED
@@ -78,7 +78,6 @@ class MLClientCtx:
78
78
  self._tmpfile = tmp
79
79
  self._logger = log_stream or logger
80
80
  self._log_level = "info"
81
- self._matrics_db = None
82
81
  self._autocommit = autocommit
83
82
  self._notifications = []
84
83
  self._state_thresholds = {}
@@ -103,8 +102,7 @@ class MLClientCtx:
103
102
  self._error = None
104
103
  self._commit = ""
105
104
  self._host = None
106
- self._start_time = now_date()
107
- self._last_update = now_date()
105
+ self._start_time = self._last_update = now_date()
108
106
  self._iteration_results = None
109
107
  self._children = []
110
108
  self._parent = None
mlrun/model.py CHANGED
@@ -1490,14 +1490,37 @@ class RunObject(RunTemplate):
1490
1490
  )
1491
1491
  return ""
1492
1492
 
1493
- def output(self, key):
1494
- """return the value of a specific result or artifact by key"""
1493
+ def output(self, key: str):
1494
+ """
1495
+ Return the value of a specific result or artifact by key.
1496
+
1497
+ This method waits for the outputs to complete and retrieves the value corresponding to the provided key.
1498
+ If the key exists in the results, it returns the corresponding result value.
1499
+ If not found in results, it attempts to fetch the artifact by key (cached in the run status).
1500
+ If the artifact is not found, it tries to fetch the artifact URI by key.
1501
+ If no artifact or result is found for the key, returns None.
1502
+
1503
+ :param key: The key of the result or artifact to retrieve.
1504
+ :return: The value of the result or the artifact URI corresponding to the key, or None if not found.
1505
+ """
1495
1506
  self._outputs_wait_for_completion()
1507
+
1508
+ # Check if the key exists in results and return the result value
1496
1509
  if self.status.results and key in self.status.results:
1497
- return self.status.results.get(key)
1510
+ return self.status.results[key]
1511
+
1512
+ # Artifacts are usually cached in the run object under `status.artifacts`. However, the artifacts are not
1513
+ # stored in the DB as part of the run. The server may enrich the run with the artifacts or provide
1514
+ # `status.artifact_uris` instead. See mlrun.common.formatters.run.RunFormat.
1515
+ # When running locally - `status.artifact_uri` does not exist in the run.
1516
+ # When listing runs - `status.artifacts` does not exist in the run.
1498
1517
  artifact = self._artifact(key)
1499
1518
  if artifact:
1500
1519
  return get_artifact_target(artifact, self.metadata.project)
1520
+
1521
+ if self.status.artifact_uris and key in self.status.artifact_uris:
1522
+ return self.status.artifact_uris[key]
1523
+
1501
1524
  return None
1502
1525
 
1503
1526
  @property
@@ -1510,26 +1533,50 @@ class RunObject(RunTemplate):
1510
1533
 
1511
1534
  @property
1512
1535
  def outputs(self):
1513
- """return a dict of outputs, result values and artifact uris"""
1514
- outputs = {}
1536
+ """
1537
+ Return a dictionary of outputs, including result values and artifact URIs.
1538
+
1539
+ This method waits for the outputs to complete and combines result values
1540
+ and artifact URIs into a single dictionary. If there are multiple artifacts
1541
+ for the same key, only include the artifact that does not have the "latest" tag.
1542
+ If there is no other tag, include the "latest" tag as a fallback.
1543
+
1544
+ :return: Dictionary containing result values and artifact URIs.
1545
+ """
1515
1546
  self._outputs_wait_for_completion()
1547
+ outputs = {}
1548
+
1549
+ # Add results if available
1516
1550
  if self.status.results:
1517
- outputs = {k: v for k, v in self.status.results.items()}
1551
+ outputs.update(self.status.results)
1552
+
1553
+ # Artifacts are usually cached in the run object under `status.artifacts`. However, the artifacts are not
1554
+ # stored in the DB as part of the run. The server may enrich the run with the artifacts or provide
1555
+ # `status.artifact_uris` instead. See mlrun.common.formatters.run.RunFormat.
1556
+ # When running locally - `status.artifact_uri` does not exist in the run.
1557
+ # When listing runs - `status.artifacts` does not exist in the run.
1518
1558
  if self.status.artifacts:
1519
- for a in self.status.artifacts:
1520
- key = a["metadata"]["key"]
1521
- outputs[key] = get_artifact_target(a, self.metadata.project)
1559
+ outputs.update(self._process_artifacts(self.status.artifacts))
1560
+ elif self.status.artifact_uris:
1561
+ outputs.update(self.status.artifact_uris)
1562
+
1522
1563
  return outputs
1523
1564
 
1524
- def artifact(self, key) -> "mlrun.DataItem":
1525
- """return artifact DataItem by key"""
1565
+ def artifact(self, key: str) -> "mlrun.DataItem":
1566
+ """Return artifact DataItem by key.
1567
+
1568
+ This method waits for the outputs to complete, searches for the artifact matching the given key,
1569
+ and returns a DataItem if the artifact is found.
1570
+
1571
+ :param key: The key of the artifact to find.
1572
+ :return: A DataItem corresponding to the artifact with the given key, or None if no such artifact is found.
1573
+ """
1526
1574
  self._outputs_wait_for_completion()
1527
1575
  artifact = self._artifact(key)
1528
- if artifact:
1529
- uri = get_artifact_target(artifact, self.metadata.project)
1530
- if uri:
1531
- return mlrun.get_dataitem(uri)
1532
- return None
1576
+ if not artifact:
1577
+ return None
1578
+ uri = get_artifact_target(artifact, self.metadata.project)
1579
+ return mlrun.get_dataitem(uri) if uri else None
1533
1580
 
1534
1581
  def _outputs_wait_for_completion(
1535
1582
  self,
@@ -1547,12 +1594,85 @@ class RunObject(RunTemplate):
1547
1594
  )
1548
1595
 
1549
1596
  def _artifact(self, key):
1550
- """return artifact DataItem by key"""
1551
- if self.status.artifacts:
1552
- for a in self.status.artifacts:
1553
- if a["metadata"]["key"] == key:
1554
- return a
1555
- return None
1597
+ """
1598
+ Return the last artifact DataItem that matches the given key.
1599
+
1600
+ If multiple artifacts with the same key exist, return the last one in the list.
1601
+ If there are artifacts with different tags, the method will return the one with a tag other than 'latest'
1602
+ if available.
1603
+ If no artifact with the given key is found, return None.
1604
+
1605
+ :param key: The key of the artifact to retrieve.
1606
+ :return: The last artifact DataItem with the given key, or None if no such artifact is found.
1607
+ """
1608
+ if not self.status.artifacts:
1609
+ return None
1610
+
1611
+ # Collect artifacts that match the key
1612
+ matching_artifacts = [
1613
+ artifact
1614
+ for artifact in self.status.artifacts
1615
+ if artifact["metadata"].get("key") == key
1616
+ ]
1617
+
1618
+ if not matching_artifacts:
1619
+ return None
1620
+
1621
+ # Sort matching artifacts by creation date in ascending order.
1622
+ # The last element in the list will be the one created most recently.
1623
+ # In case the `created` field does not exist in the artifact, that artifact will appear first in the sorted list
1624
+ matching_artifacts.sort(
1625
+ key=lambda artifact: artifact["metadata"].get("created", datetime.min)
1626
+ )
1627
+
1628
+ # Filter out artifacts with 'latest' tag
1629
+ non_latest_artifacts = [
1630
+ artifact
1631
+ for artifact in matching_artifacts
1632
+ if artifact["metadata"].get("tag") != "latest"
1633
+ ]
1634
+
1635
+ # Return the last non-'latest' artifact if available, otherwise return the last artifact
1636
+ # In the case of only one tag, `status.artifacts` includes [v1, latest]. In that case, we want to return v1.
1637
+ # In the case of multiple tags, `status.artifacts` includes [v1, latest, v2, v3].
1638
+ # In that case, we need to return the last one (v3).
1639
+ return (non_latest_artifacts or matching_artifacts)[-1]
1640
+
1641
+ def _process_artifacts(self, artifacts):
1642
+ artifacts_by_key = {}
1643
+
1644
+ # Organize artifacts by key
1645
+ for artifact in artifacts:
1646
+ key = artifact["metadata"]["key"]
1647
+ if key not in artifacts_by_key:
1648
+ artifacts_by_key[key] = []
1649
+ artifacts_by_key[key].append(artifact)
1650
+
1651
+ outputs = {}
1652
+ for key, artifacts in artifacts_by_key.items():
1653
+ # Sort matching artifacts by creation date in ascending order.
1654
+ # The last element in the list will be the one created most recently.
1655
+ # In case the `created` field does not exist in the artifactthat artifact will appear
1656
+ # first in the sorted list
1657
+ artifacts.sort(
1658
+ key=lambda artifact: artifact["metadata"].get("created", datetime.min)
1659
+ )
1660
+
1661
+ # Filter out artifacts with 'latest' tag
1662
+ non_latest_artifacts = [
1663
+ artifact
1664
+ for artifact in artifacts
1665
+ if artifact["metadata"].get("tag") != "latest"
1666
+ ]
1667
+
1668
+ # Save the last non-'latest' artifact if available, otherwise save the last artifact
1669
+ # In the case of only one tag, `artifacts` includes [v1, latest], in that case, we want to save v1.
1670
+ # In the case of multiple tags, `artifacts` includes [v1, latest, v2, v3].
1671
+ # In that case, we need to save the last one (v3).
1672
+ artifact_to_save = (non_latest_artifacts or artifacts)[-1]
1673
+ outputs[key] = get_artifact_target(artifact_to_save, self.metadata.project)
1674
+
1675
+ return outputs
1556
1676
 
1557
1677
  def uid(self):
1558
1678
  """run unique id"""
@@ -56,7 +56,7 @@ class MonitoringApplicationContext(MLClientCtx):
56
56
  def __init__(self, **kwargs):
57
57
  super().__init__(**kwargs)
58
58
 
59
- def __post_init__(self):
59
+ def _enrich_data(self):
60
60
  self.application_name: typing.Optional[str] = None
61
61
  self.start_infer_time: typing.Optional[pd.Timestamp] = None
62
62
  self.end_infer_time: typing.Optional[pd.Timestamp] = None
@@ -87,39 +87,37 @@ class MonitoringApplicationContext(MLClientCtx):
87
87
  """
88
88
 
89
89
  if not context:
90
- self = (
90
+ ctx = (
91
91
  super().from_dict(
92
92
  attrs=attrs.get(mm_constants.ApplicationEvent.MLRUN_CONTEXT, {}),
93
93
  **kwargs,
94
94
  ),
95
95
  )
96
96
  else:
97
- self = context
98
- self.__post_init__()
97
+ ctx = context
98
+ cls._enrich_data(ctx)
99
99
 
100
- self.start_infer_time = pd.Timestamp(
100
+ ctx.start_infer_time = pd.Timestamp(
101
101
  attrs.get(mm_constants.ApplicationEvent.START_INFER_TIME)
102
102
  )
103
- self.end_infer_time = pd.Timestamp(
103
+ ctx.end_infer_time = pd.Timestamp(
104
104
  attrs.get(mm_constants.ApplicationEvent.END_INFER_TIME)
105
105
  )
106
- self.latest_request = pd.Timestamp(
106
+ ctx.latest_request = pd.Timestamp(
107
107
  attrs.get(mm_constants.ApplicationEvent.LAST_REQUEST)
108
108
  )
109
- self.application_name = attrs.get(
110
- mm_constants.ApplicationEvent.APPLICATION_NAME
111
- )
112
- self._feature_stats = json.loads(
109
+ ctx.application_name = attrs.get(mm_constants.ApplicationEvent.APPLICATION_NAME)
110
+ ctx._feature_stats = json.loads(
113
111
  attrs.get(mm_constants.ApplicationEvent.FEATURE_STATS, "{}")
114
112
  )
115
- self._sample_df_stats = json.loads(
113
+ ctx._sample_df_stats = json.loads(
116
114
  attrs.get(mm_constants.ApplicationEvent.CURRENT_STATS, "{}")
117
115
  )
118
116
 
119
- self.endpoint_id = attrs.get(mm_constants.ApplicationEvent.ENDPOINT_ID)
120
- self._model_endpoint = model_endpoint_dict.get(self.endpoint_id)
117
+ ctx.endpoint_id = attrs.get(mm_constants.ApplicationEvent.ENDPOINT_ID)
118
+ ctx._model_endpoint = model_endpoint_dict.get(ctx.endpoint_id)
121
119
 
122
- return self
120
+ return ctx
123
121
 
124
122
  @property
125
123
  def sample_df(self) -> pd.DataFrame:
mlrun/projects/project.py CHANGED
@@ -725,7 +725,7 @@ def _project_instance_from_struct(struct, name, allow_cross_project):
725
725
  # TODO: Remove this warning in version 1.9.0 and also fix cli to support allow_cross_project
726
726
  warnings.warn(
727
727
  f"Project {name=} is different than specified on the context's project yaml. "
728
- "This behavior is deprecated and will not be supported in version 1.9.0."
728
+ "This behavior is deprecated and will not be supported from version 1.9.0."
729
729
  )
730
730
  logger.warn(error_message)
731
731
  elif allow_cross_project:
@@ -4063,6 +4063,12 @@ class MlrunProject(ModelObj):
4063
4063
  db = mlrun.db.get_run_db(secrets=self._secrets)
4064
4064
  if alert_name is None:
4065
4065
  alert_name = alert_data.name
4066
+ if alert_data.project is not None and alert_data.project != self.metadata.name:
4067
+ logger.warn(
4068
+ "Project in alert does not match project in operation",
4069
+ project=alert_data.project,
4070
+ )
4071
+ alert_data.project = self.metadata.name
4066
4072
  return db.store_alert_config(alert_name, alert_data, project=self.metadata.name)
4067
4073
 
4068
4074
  def get_alert_config(self, alert_name: str) -> AlertConfig:
mlrun/run.py CHANGED
@@ -21,6 +21,7 @@ import tempfile
21
21
  import time
22
22
  import typing
23
23
  import uuid
24
+ import warnings
24
25
  from base64 import b64decode
25
26
  from copy import deepcopy
26
27
  from os import environ, makedirs, path
@@ -196,18 +197,19 @@ def load_func_code(command="", workdir=None, secrets=None, name="name"):
196
197
  def get_or_create_ctx(
197
198
  name: str,
198
199
  event=None,
199
- spec=None,
200
+ spec: Optional[dict] = None,
200
201
  with_env: bool = True,
201
202
  rundb: str = "",
202
203
  project: str = "",
203
- upload_artifacts=False,
204
+ upload_artifacts: bool = False,
204
205
  labels: Optional[dict] = None,
205
206
  ) -> MLClientCtx:
206
- """called from within the user program to obtain a run context
207
+ """
208
+ Called from within the user program to obtain a run context.
207
209
 
208
- the run context is an interface for receiving parameters, data and logging
210
+ The run context is an interface for receiving parameters, data and logging
209
211
  run results, the run context is read from the event, spec, or environment
210
- (in that order), user can also work without a context (local defaults mode)
212
+ (in that order), user can also work without a context (local defaults mode).
211
213
 
212
214
  all results are automatically stored in the "rundb" or artifact store,
213
215
  the path to the rundb can be specified in the call or obtained from env.
@@ -220,7 +222,7 @@ def get_or_create_ctx(
220
222
  :param project: project to initiate the context in (by default `mlrun.mlconf.default_project`)
221
223
  :param upload_artifacts: when using local context (not as part of a job/run), upload artifacts to the
222
224
  system default artifact path location
223
- :param labels: dict of the context labels
225
+ :param labels: (deprecated - use spec instead) dict of the context labels.
224
226
  :return: execution context
225
227
 
226
228
  Examples::
@@ -253,6 +255,20 @@ def get_or_create_ctx(
253
255
  context.log_artifact("results.html", body=b"<b> Some HTML <b>", viewer="web-app")
254
256
 
255
257
  """
258
+ if labels:
259
+ warnings.warn(
260
+ "The `labels` argument is deprecated and will be removed in 1.9.0. "
261
+ "Please use `spec` instead, e.g.:\n"
262
+ "spec={'metadata': {'labels': {'key': 'value'}}}",
263
+ FutureWarning,
264
+ )
265
+ if spec is None:
266
+ spec = {}
267
+ if "metadata" not in spec:
268
+ spec["metadata"] = {}
269
+ if "labels" not in spec["metadata"]:
270
+ spec["metadata"]["labels"] = {}
271
+ spec["metadata"]["labels"].update(labels)
256
272
 
257
273
  if global_context.get() and not spec and not event:
258
274
  return global_context.get()
@@ -306,9 +322,6 @@ def get_or_create_ctx(
306
322
  ctx = MLClientCtx.from_dict(
307
323
  newspec, rundb=out, autocommit=autocommit, tmp=tmp, host=socket.gethostname()
308
324
  )
309
- labels = labels or {}
310
- for key, val in labels.items():
311
- ctx.set_label(key=key, value=val)
312
325
  global_context.set(ctx)
313
326
  return ctx
314
327
 
@@ -326,6 +326,11 @@ class APIGatewaySpec(ModelObj):
326
326
  return function_names
327
327
 
328
328
 
329
+ class APIGatewayStatus(ModelObj):
330
+ def __init__(self, state: Optional[schemas.APIGatewayState] = None):
331
+ self.state = state or schemas.APIGatewayState.none
332
+
333
+
329
334
  class APIGateway(ModelObj):
330
335
  _dict_fields = [
331
336
  "metadata",
@@ -338,16 +343,18 @@ class APIGateway(ModelObj):
338
343
  self,
339
344
  metadata: APIGatewayMetadata,
340
345
  spec: APIGatewaySpec,
346
+ status: Optional[APIGatewayStatus] = None,
341
347
  ):
342
348
  """
343
349
  Initialize the APIGateway instance.
344
350
 
345
351
  :param metadata: (APIGatewayMetadata) The metadata of the API gateway.
346
352
  :param spec: (APIGatewaySpec) The spec of the API gateway.
353
+ :param status: (APIGatewayStatus) The status of the API gateway.
347
354
  """
348
355
  self.metadata = metadata
349
356
  self.spec = spec
350
- self.state = ""
357
+ self.status = status
351
358
 
352
359
  @property
353
360
  def metadata(self) -> APIGatewayMetadata:
@@ -365,6 +372,14 @@ class APIGateway(ModelObj):
365
372
  def spec(self, spec):
366
373
  self._spec = self._verify_dict(spec, "spec", APIGatewaySpec)
367
374
 
375
+ @property
376
+ def status(self) -> APIGatewayStatus:
377
+ return self._status
378
+
379
+ @status.setter
380
+ def status(self, status):
381
+ self._status = self._verify_dict(status, "status", APIGatewayStatus)
382
+
368
383
  def invoke(
369
384
  self,
370
385
  method="POST",
@@ -394,7 +409,7 @@ class APIGateway(ModelObj):
394
409
  )
395
410
  if not self.is_ready():
396
411
  raise mlrun.errors.MLRunPreconditionFailedError(
397
- f"API gateway is not ready. " f"Current state: {self.state}"
412
+ f"API gateway is not ready. " f"Current state: {self.status.state}"
398
413
  )
399
414
 
400
415
  auth = None
@@ -459,10 +474,10 @@ class APIGateway(ModelObj):
459
474
  )
460
475
 
461
476
  def is_ready(self):
462
- if self.state is not schemas.api_gateway.APIGatewayState.ready:
477
+ if self.status.state is not schemas.api_gateway.APIGatewayState.ready:
463
478
  # try to sync the state
464
479
  self.sync()
465
- return self.state == schemas.api_gateway.APIGatewayState.ready
480
+ return self.status.state == schemas.api_gateway.APIGatewayState.ready
466
481
 
467
482
  def sync(self):
468
483
  """
@@ -479,7 +494,7 @@ class APIGateway(ModelObj):
479
494
  self.spec.functions = synced_gateway.spec.functions
480
495
  self.spec.canary = synced_gateway.spec.canary
481
496
  self.spec.description = synced_gateway.spec.description
482
- self.state = synced_gateway.state
497
+ self.status.state = synced_gateway.status.state
483
498
 
484
499
  def with_basic_auth(self, username: str, password: str):
485
500
  """
@@ -580,8 +595,8 @@ class APIGateway(ModelObj):
580
595
  functions=functions,
581
596
  canary=canary,
582
597
  ),
598
+ status=APIGatewayStatus(state=state),
583
599
  )
584
- new_api_gateway.state = state
585
600
  return new_api_gateway
586
601
 
587
602
  def to_scheme(self) -> schemas.APIGateway:
@@ -625,6 +640,7 @@ class APIGateway(ModelObj):
625
640
  ),
626
641
  upstreams=upstreams,
627
642
  ),
643
+ status=schemas.APIGatewayStatus(state=self.status.state),
628
644
  )
629
645
  api_gateway.spec.authentication = self.spec.authentication.to_scheme()
630
646
  return api_gateway
@@ -149,6 +149,7 @@ class ApplicationStatus(NuclioStatus):
149
149
  build_pod=None,
150
150
  container_image=None,
151
151
  application_image=None,
152
+ application_source=None,
152
153
  sidecar_name=None,
153
154
  api_gateway_name=None,
154
155
  api_gateway=None,
@@ -164,6 +165,7 @@ class ApplicationStatus(NuclioStatus):
164
165
  container_image=container_image,
165
166
  )
166
167
  self.application_image = application_image or None
168
+ self.application_source = application_source or None
167
169
  self.sidecar_name = sidecar_name or None
168
170
  self.api_gateway_name = api_gateway_name or None
169
171
  self.api_gateway = api_gateway or None
@@ -317,15 +319,25 @@ class ApplicationRuntime(RemoteRuntime):
317
319
  )
318
320
 
319
321
  super().deploy(
320
- project,
321
- tag,
322
- verbose,
323
- auth_info,
324
- builder_env,
322
+ project=project,
323
+ tag=tag,
324
+ verbose=verbose,
325
+ auth_info=auth_info,
326
+ builder_env=builder_env,
327
+ )
328
+ logger.info(
329
+ "Successfully deployed function, creating API gateway",
330
+ api_gateway_name=self.status.api_gateway_name,
331
+ authentication_mode=authentication_mode,
325
332
  )
326
333
 
334
+ # Restore the source in case it was removed to make nuclio not consider it when building
335
+ if not self.spec.build.source and self.status.application_source:
336
+ self.spec.build.source = self.status.application_source
337
+ self.save(versioned=False)
338
+
327
339
  ports = self.spec.internal_application_port if direct_port_access else []
328
- self.create_api_gateway(
340
+ return self.create_api_gateway(
329
341
  name=self.status.api_gateway_name,
330
342
  ports=ports,
331
343
  authentication_mode=authentication_mode,
@@ -354,6 +366,14 @@ class ApplicationRuntime(RemoteRuntime):
354
366
  target_dir=target_dir,
355
367
  )
356
368
 
369
+ def from_image(self, image):
370
+ super().from_image(image)
371
+ # nuclio implementation detail - when providing the image and emptying out the source code and build source,
372
+ # nuclio skips rebuilding the image and simply takes the prebuilt image
373
+ self.spec.build.functionSourceCode = ""
374
+ self.status.application_source = self.spec.build.source
375
+ self.spec.build.source = ""
376
+
357
377
  @classmethod
358
378
  def get_filename_and_handler(cls) -> (str, str):
359
379
  reverse_proxy_file_path = pathlib.Path(__file__).parent / "reverse_proxy.go"
@@ -409,6 +429,9 @@ class ApplicationRuntime(RemoteRuntime):
409
429
  self.status.api_gateway.wait_for_readiness()
410
430
  self.url = self.status.api_gateway.invoke_url
411
431
 
432
+ logger.info("Successfully created API gateway", url=self.url)
433
+ return self.url
434
+
412
435
  def invoke(
413
436
  self,
414
437
  path: str,
@@ -448,6 +471,14 @@ class ApplicationRuntime(RemoteRuntime):
448
471
  **http_client_kwargs,
449
472
  )
450
473
 
474
+ def _run(self, runobj: "mlrun.RunObject", execution):
475
+ raise mlrun.runtimes.RunError(
476
+ "Application runtime .run() is not yet supported. Use .invoke() instead."
477
+ )
478
+
479
+ def _enrich_command_from_status(self):
480
+ pass
481
+
451
482
  def _build_application_image(
452
483
  self,
453
484
  builder_env: dict = None,
@@ -506,9 +537,6 @@ class ApplicationRuntime(RemoteRuntime):
506
537
 
507
538
  if self.status.container_image:
508
539
  self.from_image(self.status.container_image)
509
- # nuclio implementation detail - when providing the image and emptying out the source code,
510
- # nuclio skips rebuilding the image and simply takes the prebuilt image
511
- self.spec.build.functionSourceCode = ""
512
540
 
513
541
  self.status.sidecar_name = f"{self.metadata.name}-sidecar"
514
542
  self.with_sidecar(
@@ -568,6 +568,9 @@ class RemoteRuntime(KubeResource):
568
568
  # this also means that the function object will be updated with the function status
569
569
  self._wait_for_function_deployment(db, verbose=verbose)
570
570
 
571
+ return self._enrich_command_from_status()
572
+
573
+ def _enrich_command_from_status(self):
571
574
  # NOTE: on older mlrun versions & nuclio versions, function are exposed via NodePort
572
575
  # now, functions can be not exposed (using service type ClusterIP) and hence
573
576
  # for BC we first try to populate the external invocation url, and then
@@ -325,12 +325,12 @@ class ServingRuntime(RemoteRuntime):
325
325
  :param enable_tracking: Enabled/Disable model-monitoring tracking.
326
326
  Default True (tracking enabled).
327
327
 
328
- example::
328
+ Example::
329
329
 
330
- # initialize a new serving function
331
- serving_fn = mlrun.import_function("hub://v2-model-server", new_name="serving")
332
- # apply model monitoring
333
- serving_fn.set_tracking()
330
+ # initialize a new serving function
331
+ serving_fn = mlrun.import_function("hub://v2-model-server", new_name="serving")
332
+ # apply model monitoring
333
+ serving_fn.set_tracking()
334
334
 
335
335
  """
336
336
  # Applying model monitoring configurations
mlrun/serving/server.py CHANGED
@@ -321,9 +321,9 @@ def v2_serving_init(context, namespace=None):
321
321
  server.http_trigger = getattr(context.trigger, "kind", "http") == "http"
322
322
  context.logger.info_with(
323
323
  "Setting current function",
324
- current_functiton=os.environ.get("SERVING_CURRENT_FUNCTION", ""),
324
+ current_function=os.getenv("SERVING_CURRENT_FUNCTION", ""),
325
325
  )
326
- server.set_current_function(os.environ.get("SERVING_CURRENT_FUNCTION", ""))
326
+ server.set_current_function(os.getenv("SERVING_CURRENT_FUNCTION", ""))
327
327
  context.logger.info_with(
328
328
  "Initializing states", namespace=namespace or get_caller_globals()
329
329
  )
@@ -344,9 +344,14 @@ def v2_serving_init(context, namespace=None):
344
344
  if server.verbose:
345
345
  context.logger.info(server.to_yaml())
346
346
 
347
- if hasattr(context, "platform") and hasattr(
348
- context.platform, "set_termination_callback"
349
- ):
347
+ _set_callbacks(server, context)
348
+
349
+
350
+ def _set_callbacks(server, context):
351
+ if not server.graph.supports_termination() or not hasattr(context, "platform"):
352
+ return
353
+
354
+ if hasattr(context.platform, "set_termination_callback"):
350
355
  context.logger.info(
351
356
  "Setting termination callback to terminate graph on worker shutdown"
352
357
  )
@@ -358,7 +363,7 @@ def v2_serving_init(context, namespace=None):
358
363
 
359
364
  context.platform.set_termination_callback(termination_callback)
360
365
 
361
- if hasattr(context, "platform") and hasattr(context.platform, "set_drain_callback"):
366
+ if hasattr(context.platform, "set_drain_callback"):
362
367
  context.logger.info(
363
368
  "Setting drain callback to terminate and restart the graph on a drain event (such as rebalancing)"
364
369
  )
@@ -417,7 +422,7 @@ def create_graph_server(
417
422
  parameters = parameters or {}
418
423
  server = GraphServer(graph, parameters, load_mode, verbose=verbose, **kwargs)
419
424
  server.set_current_function(
420
- current_function or os.environ.get("SERVING_CURRENT_FUNCTION", "")
425
+ current_function or os.getenv("SERVING_CURRENT_FUNCTION", "")
421
426
  )
422
427
  return server
423
428
 
mlrun/serving/states.py CHANGED
@@ -27,6 +27,8 @@ from copy import copy, deepcopy
27
27
  from inspect import getfullargspec, signature
28
28
  from typing import Any, Union
29
29
 
30
+ import storey.utils
31
+
30
32
  import mlrun
31
33
 
32
34
  from ..config import config
@@ -386,6 +388,9 @@ class BaseStep(ModelObj):
386
388
  """
387
389
  raise NotImplementedError("set_flow() can only be called on a FlowStep")
388
390
 
391
+ def supports_termination(self):
392
+ return False
393
+
389
394
 
390
395
  class TaskStep(BaseStep):
391
396
  """task execution step, runs a class or handler"""
@@ -867,7 +872,9 @@ class QueueStep(BaseStep):
867
872
  return event
868
873
 
869
874
  if self._stream:
870
- self._stream.push({"id": event.id, "body": data, "path": event.path})
875
+ if self.options.get("full_event", True):
876
+ data = storey.utils.wrap_event_for_serialization(event, data)
877
+ self._stream.push(data)
871
878
  event.terminated = True
872
879
  event.body = None
873
880
  return event
@@ -1273,6 +1280,8 @@ class FlowStep(BaseStep):
1273
1280
  event.body = {"id": event.id}
1274
1281
  return event
1275
1282
 
1283
+ event = storey.utils.unpack_event_if_wrapped(event)
1284
+
1276
1285
  if len(self._start_steps) == 0:
1277
1286
  return event
1278
1287
  next_obj = self._start_steps[0]
@@ -1380,6 +1389,9 @@ class FlowStep(BaseStep):
1380
1389
 
1381
1390
  return step
1382
1391
 
1392
+ def supports_termination(self):
1393
+ return self.engine == "async"
1394
+
1383
1395
 
1384
1396
  class RootFlowStep(FlowStep):
1385
1397
  """root flow step"""
mlrun/utils/db.py CHANGED
@@ -28,6 +28,9 @@ class BaseModel:
28
28
  columns = [column.key for column in mapper.columns if column.key not in exclude]
29
29
 
30
30
  def get_key_value(c):
31
+ # all (never say never) DB classes have "object" defined as "full_object"
32
+ if c == "object":
33
+ c = "full_object"
31
34
  if isinstance(getattr(self, c), datetime):
32
35
  return c, getattr(self, c).isoformat()
33
36
  return c, getattr(self, c)
mlrun/utils/helpers.py CHANGED
@@ -111,13 +111,11 @@ def get_artifact_target(item: dict, project=None):
111
111
  tree = item["metadata"].get("tree")
112
112
  tag = item["metadata"].get("tag")
113
113
 
114
- kind = item.get("kind")
115
- if kind in ["dataset", "model", "artifact"] and db_key:
114
+ if item.get("kind") in {"dataset", "model", "artifact"} and db_key:
116
115
  target = f"{DB_SCHEMA}://{StorePrefix.Artifact}/{project_str}/{db_key}"
117
- if tag:
118
- target = f"{target}:{tag}"
116
+ target += f":{tag}" if tag else ":latest"
119
117
  if tree:
120
- target = f"{target}@{tree}"
118
+ target += f"@{tree}"
121
119
  return target
122
120
 
123
121
  return item["spec"].get("target_path")
@@ -60,7 +60,14 @@ class WebhookNotification(NotificationBase):
60
60
  request_body["runs"] = runs
61
61
 
62
62
  if alert:
63
- request_body["alert"] = alert.dict()
63
+ request_body["name"] = alert.name
64
+ request_body["project"] = alert.project
65
+ request_body["severity"] = alert.severity
66
+ if alert.summary:
67
+ request_body["summary"] = mlrun.utils.helpers.format_alert_summary(
68
+ alert, event_data
69
+ )
70
+
64
71
  if event_data:
65
72
  request_body["value"] = event_data.value_dict
66
73
  request_body["id"] = event_data.entity.ids[0]
@@ -1,4 +1,4 @@
1
1
  {
2
- "git_commit": "bf08d974e49838643bae063182b41e12f05f1a2b",
3
- "version": "1.7.0-rc33"
2
+ "git_commit": "4542af29f22f596b4e09be897f728a6e8f676b55",
3
+ "version": "1.7.0-rc34"
4
4
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mlrun
3
- Version: 1.7.0rc33
3
+ Version: 1.7.0rc34
4
4
  Summary: Tracking and config of machine learning runs
5
5
  Home-page: https://github.com/mlrun/mlrun
6
6
  Author: Yaron Haviv
@@ -43,7 +43,7 @@ Requires-Dist: semver ~=3.0
43
43
  Requires-Dist: dependency-injector ~=4.41
44
44
  Requires-Dist: fsspec <2024.4,>=2023.9.2
45
45
  Requires-Dist: v3iofs ~=0.1.17
46
- Requires-Dist: storey ~=1.7.20
46
+ Requires-Dist: storey ~=1.7.23
47
47
  Requires-Dist: inflection ~=0.5.0
48
48
  Requires-Dist: python-dotenv ~=0.17.0
49
49
  Requires-Dist: setuptools ~=71.0
@@ -2,13 +2,13 @@ mlrun/__init__.py,sha256=y08M1JcKXy5-9_5WaI9fn5aV5BxIQ5QkbduJK0OxWbA,7470
2
2
  mlrun/__main__.py,sha256=iAifncsrQQx6ozXXmz7GH1OiNl8PA7KS3TnwlxnHGeo,45890
3
3
  mlrun/config.py,sha256=5QrlkkUosFwziSFTtApeB2obpS-gW126lB8y5za7rhM,66103
4
4
  mlrun/errors.py,sha256=VpC_imeSz2twRMZZb7u90Zj29z6aO-tCxUHD3ZA_Axw,7465
5
- mlrun/execution.py,sha256=StasIZWmnbRjXDn5d7VU6DWu1fs_AJQckSiUKlSYL9M,42021
5
+ mlrun/execution.py,sha256=Gv7mzzaf5y8fIEF0VVu8dSJYQp2uCezXDUiE60cGxWU,41970
6
6
  mlrun/features.py,sha256=m17K_3l9Jktwb9dOwlHLTAPTlemsWrRF7dJhXUX0iJU,15429
7
7
  mlrun/k8s_utils.py,sha256=WdUajadvAhTR7sAMQdwFqKeJMimuTyqm02VdwK1A4xU,7023
8
8
  mlrun/lists.py,sha256=3PqBdcajdwhTe1XuFsAaHTuFVM2kjwepf31qqE82apg,8384
9
- mlrun/model.py,sha256=AtpmCoJV9yCu4ifPxtb5n9sv_alOhiLyASAxJdLkIr0,73197
9
+ mlrun/model.py,sha256=QA-Wi3Po5OB9Y7aR-vEFjLT4dkU-597QM4qAEmv-UvI,79092
10
10
  mlrun/render.py,sha256=n8SeY3ogVrsV02-7-H0lt1RmpkxGpbI-11RQx61Vq9E,13267
11
- mlrun/run.py,sha256=1fBaemIeTg9xpXF_THQb_x0bSAq_4xmC9s-PeDd-IC0,42911
11
+ mlrun/run.py,sha256=uIHNQ-OSrviNwkZ54cQy27SIO62WIaFHdwz08K5NwK0,43410
12
12
  mlrun/secrets.py,sha256=ibtCK79u7JVBZF6F0SP1-xXXF5MyrLEUs_TCWiJAnlc,7798
13
13
  mlrun/alerts/__init__.py,sha256=0gtG1BG0DXxFrXegIkjbM1XEN4sP9ODo0ucXrNld1hU,601
14
14
  mlrun/alerts/alert.py,sha256=JJfMFF-o0j8oTAIkyXAQG0YbU-kZlIDl0A8ILQi8vfA,6510
@@ -36,7 +36,7 @@ mlrun/common/formatters/run.py,sha256=eEBy1NEwGT9b98TWS2OetEbDnDrnHBIBVMrlXsxveo
36
36
  mlrun/common/model_monitoring/__init__.py,sha256=x0EMEvxVjHsm858J1t6IEA9dtKTdFpJ9sKhss10ld8A,721
37
37
  mlrun/common/model_monitoring/helpers.py,sha256=1CpxIDQPumFnpUB1eqcvCpLlyPFVeW2sL6prM-N5A1A,4405
38
38
  mlrun/common/runtimes/constants.py,sha256=Rl0Sd8n_L7Imo-uF1LL9CJ5Szi0W1gUm36yrF8PXfSc,10989
39
- mlrun/common/schemas/__init__.py,sha256=uqXeeg275X7NlM9FrH5JBORLA5s87P8MSrd7fwPoTlY,5236
39
+ mlrun/common/schemas/__init__.py,sha256=txPKk2yW6vpyIc6ri48JD0vBwFpZfSdW3CFjVp7XDl0,5252
40
40
  mlrun/common/schemas/alert.py,sha256=Gb2eSjZLTkm-lGy_rQ_D4crEjCTdyf1N90bnIJmQ1H8,6574
41
41
  mlrun/common/schemas/api_gateway.py,sha256=_1JyCFNP89dAcFxQE-C8Tj8o6TvPgV13aBzU3wRcM4g,6908
42
42
  mlrun/common/schemas/artifact.py,sha256=V3ngobnzI1v2eoOroWBEedjAZu0ntCSIQ-LzsOK1Z9k,3570
@@ -44,13 +44,13 @@ mlrun/common/schemas/auth.py,sha256=5c4WSn3KdX1v04ttSQblkF_gyjdjuJSHG7BTCx4_LWM,
44
44
  mlrun/common/schemas/background_task.py,sha256=2qZxib2qrF_nPZj0ncitCG-2jxz2hg1qj0hFc8eswWQ,1707
45
45
  mlrun/common/schemas/client_spec.py,sha256=xQ_9S5i5q7vJmkp2_3IYD0FSYnWoAr1k-W9MU2ClgEU,2955
46
46
  mlrun/common/schemas/clusterization_spec.py,sha256=aeaFJZms7r7h2HDv6ML_GDAT6gboW-PxBbc3GKPalGk,888
47
- mlrun/common/schemas/common.py,sha256=00upzVLPN7O511Q87yt-fvRcDQFbXra4j0_lqMGg6rs,1557
47
+ mlrun/common/schemas/common.py,sha256=nxtZDzs92-p0wygIhQ_SEU3J9QsJRKE4RsY18olLXyo,1613
48
48
  mlrun/common/schemas/constants.py,sha256=sTNCimttd7ytSZ3jxbftItw_HDGxPwY96Ub86OvcT9w,6660
49
49
  mlrun/common/schemas/datastore_profile.py,sha256=hJ8q54A8VZKsnOvSIjcllj4MZ1bBhb_EmBgsqpwSF_Y,750
50
50
  mlrun/common/schemas/events.py,sha256=ROHJLo_fqYjc96pek7yhAUPpPRIuAR76lwxvNz8LIr8,1026
51
51
  mlrun/common/schemas/feature_store.py,sha256=T0yKYcv6cb3ZwgY5Jh9kWp94zLv2ImxAQUy6x68Imd0,4776
52
52
  mlrun/common/schemas/frontend_spec.py,sha256=CNPq3YV0U1jCbCMbb84_Oid2Snow5EXYt1F5wsuhgD8,2454
53
- mlrun/common/schemas/function.py,sha256=Khd5Jd6ept1nHWkW1WdIy1u8iK4O8_Ddf3a7cv3Hf1I,4652
53
+ mlrun/common/schemas/function.py,sha256=fZZBZroj6Ok0giRn2pYSzR40bx037v9pIWvSagPA2fE,4820
54
54
  mlrun/common/schemas/http.py,sha256=1PtYFhF6sqLSBRcuPMtYcUGmroBhaleqLmYidSdL9LM,705
55
55
  mlrun/common/schemas/hub.py,sha256=cuv_vpkO27XNCZzfytnUyi0k0ZA4wf_QRn5B0ZPoK-Y,4116
56
56
  mlrun/common/schemas/k8s.py,sha256=nmMnhgjVMLem5jyumoG2eQKioGK9eUVhQnOSb3hG7yw,1395
@@ -59,7 +59,7 @@ mlrun/common/schemas/notification.py,sha256=Ge7eWNGf_XUFkjOnUkyUOubdEbmXh9z_OSGc
59
59
  mlrun/common/schemas/object.py,sha256=VleJSUmDJMl92knLgaDE8SWCi3ky0UaHcwcwOIapPQ8,1980
60
60
  mlrun/common/schemas/pagination.py,sha256=q7nk6bipkDiE7HExIVqhy5ANl-zv0x8QC9Kg6AkLtDA,887
61
61
  mlrun/common/schemas/pipeline.py,sha256=MhH07_fAQXNAnmf5j6oXZp8qh9cxGcZlReMdt-ZJf40,1429
62
- mlrun/common/schemas/project.py,sha256=wQAq6TAELf2_9qhLBTJ6Ofntdybx5Fbhy2uBsUzEmrk,4976
62
+ mlrun/common/schemas/project.py,sha256=WSkiuZx3IBfYmur9DE3qSZGrY8z_BQWdRhAo7gdnuMU,6313
63
63
  mlrun/common/schemas/regex.py,sha256=8_vbDeAE0SODJDj7yUFg1FbaB9CNydYQTJ29JxE74Kc,776
64
64
  mlrun/common/schemas/runs.py,sha256=yGGJxSHT_Mq4RLjlfuxW4pm9i-Py9eOsGUAofs_VqVM,1268
65
65
  mlrun/common/schemas/runtime_resource.py,sha256=2rSuYL-9JkESSomlnU91mYDbfV-IkqZeXx6OHuMmDxs,1554
@@ -101,9 +101,9 @@ mlrun/datastore/wasbfs/__init__.py,sha256=s5Ul-0kAhYqFjKDR2X0O2vDGDbLQQduElb32Ev
101
101
  mlrun/datastore/wasbfs/fs.py,sha256=MnSj7Q4OKA2L55ihCmUnj2t3GA3B77oLMdAw-yxvN9w,6151
102
102
  mlrun/db/__init__.py,sha256=WqJ4x8lqJ7ZoKbhEyFqkYADd9P6E3citckx9e9ZLcIU,1163
103
103
  mlrun/db/auth_utils.py,sha256=hpg8D2r82oN0BWabuWN04BTNZ7jYMAF242YSUpK7LFM,5211
104
- mlrun/db/base.py,sha256=8GVa4WlswPcUjnidwazRhIjKbaI2aqeQ8MmHr62ih1k,24085
104
+ mlrun/db/base.py,sha256=cHMkIJW1cnhIH8dxVjZTusUDsFirtKaEjDuF7he0VWM,24185
105
105
  mlrun/db/factory.py,sha256=ibIrE5QkIIyzDU1FXKrfbc31cZiRLYKDZb8dqCpQwyU,2397
106
- mlrun/db/httpdb.py,sha256=qy0uERFBfTklXmrRpxCC2dJSv7xtyz1bvP2eK1Yf-xE,183765
106
+ mlrun/db/httpdb.py,sha256=ivOg9Sy5HVT62nhIis365KhNrsWS5sS-rgLZ33Tc-7I,183980
107
107
  mlrun/db/nopdb.py,sha256=d7vSk_2sfwZGY24w7ucSkoq88fLPDLF137IXabongXU,20791
108
108
  mlrun/feature_store/__init__.py,sha256=FhHRc8NdqL_HWpCs7A8dKruxJS5wEm55Gs3dcgBiRUg,1522
109
109
  mlrun/feature_store/api.py,sha256=uYheyPkJOVCrz1jivvpGatgy_JBAq0It0XZqPpNVQkE,48699
@@ -224,7 +224,7 @@ mlrun/model_monitoring/writer.py,sha256=aQ1DAi5XUi1WXXfcSgBQGKiTANT6E61I74abiu_5
224
224
  mlrun/model_monitoring/applications/__init__.py,sha256=i793GqYee01mRh_KD6GShvX7UbPBgdJDO4qf9Z3BXEQ,970
225
225
  mlrun/model_monitoring/applications/_application_steps.py,sha256=-g9jxIAFM5f22iJaUAQVlM8QRSv6KFT92I4WHmZe_f0,6028
226
226
  mlrun/model_monitoring/applications/base.py,sha256=buVKyghH4AB3chZ5py1vyMIFnTF-deY8YDf_fPC9BnQ,11307
227
- mlrun/model_monitoring/applications/context.py,sha256=i-9h6pWyrS8mjw53zd0kb_Dsf9ReS8cSfnth8PvOEI4,8571
227
+ mlrun/model_monitoring/applications/context.py,sha256=LGRJdI1eyyssFzjE4W_rk2VAUV8KpOkUZUX3xCmnC9g,8537
228
228
  mlrun/model_monitoring/applications/evidently_base.py,sha256=AE_eIz-GEYm3AZTrMCiqF9bcSMlvYk08LJb6bKWAQLg,8057
229
229
  mlrun/model_monitoring/applications/histogram_data_drift.py,sha256=TE6995h2PyO4lytVngH2HidhXFY7reLupWi4cHmdZdw,13163
230
230
  mlrun/model_monitoring/applications/results.py,sha256=VVlu9Si7Tj2LNJzPQrp4_Qeyh9mxOVMu1Jwb5K2LfvY,3577
@@ -274,7 +274,7 @@ mlrun/platforms/iguazio.py,sha256=1h5BpdAEQJBg2vIt7ySjUADU0ip5OkaMYr0_VREi9ys,13
274
274
  mlrun/projects/__init__.py,sha256=Lv5rfxyXJrw6WGOWJKhBz66M6t3_zsNMCfUD6waPwx4,1153
275
275
  mlrun/projects/operations.py,sha256=Y-NwrIFXpltUXcDLDQ9b33NY_r4TOPvJgO4F-xSuzoM,19252
276
276
  mlrun/projects/pipelines.py,sha256=Xc9tQSBBPEg1Yxn-b4RseFdfO7SvrYC-ekdw_hAcPH8,40006
277
- mlrun/projects/project.py,sha256=pmZuqi24YV9E14QlllwhEtCTkthSF5wkI9NlQXllH7U,184395
277
+ mlrun/projects/project.py,sha256=ROcuNkjV6kA8oGrnk4-MFj_0h5D04af9oWmXqVq7-lg,184688
278
278
  mlrun/runtimes/__init__.py,sha256=0-tYDkew-Cr4DM-wztvMbzDA5xq385Jjo-GrtO_84Sc,8741
279
279
  mlrun/runtimes/base.py,sha256=g716uF0BpL6vLe75bNqpJ2SjtYW_tQqICl46d_4ljHs,37633
280
280
  mlrun/runtimes/daskjob.py,sha256=JfK8rSPY-0SYnLJdtp_ts3oKyad0pA98th-2VntYzK0,19387
@@ -294,12 +294,12 @@ mlrun/runtimes/mpijob/__init__.py,sha256=V_1gQD1VHa0Qvjqgyv8RLouH27Sy9YTwj2ZG62o
294
294
  mlrun/runtimes/mpijob/abstract.py,sha256=kDWo-IY1FKLZhI30j38Xx9HMhlUvHezfd1DT2ShoxZY,9161
295
295
  mlrun/runtimes/mpijob/v1.py,sha256=1XQZC7AIMGX_AQCbApcwpH8I7y39-v0v2O35MvxjXoo,3213
296
296
  mlrun/runtimes/nuclio/__init__.py,sha256=gx1kizzKv8pGT5TNloN1js1hdbxqDw3rM90sLVYVffY,794
297
- mlrun/runtimes/nuclio/api_gateway.py,sha256=CTYPcdocMrQQiCk08jbC_nNF0jlwTQ2WKxRsC_fz_ms,25155
298
- mlrun/runtimes/nuclio/function.py,sha256=8RhCvwC_24eSxFaL7Yb5tiRiJaV4H_xTmJ0QiWNIPw8,50317
297
+ mlrun/runtimes/nuclio/api_gateway.py,sha256=TsEZFv-Ene2WZCS9jKReVmuMil_kIbcr9eFmmLxgsYU,25781
298
+ mlrun/runtimes/nuclio/function.py,sha256=Y-lNSQJXzsYXu4wCVOB69fv_X9ZvB-uwS1UZhbQPucE,50411
299
299
  mlrun/runtimes/nuclio/nuclio.py,sha256=sLK8KdGO1LbftlL3HqPZlFOFTAAuxJACZCVl1c0Ha6E,2942
300
- mlrun/runtimes/nuclio/serving.py,sha256=ucSDp2YbaKEFpuCxCTEPwOEPngPkuP-TRviHJ9J4D60,29866
300
+ mlrun/runtimes/nuclio/serving.py,sha256=qefcNtvAETt5otI4NymZnY_5Su6MTHmI35WHZsrCqww,29746
301
301
  mlrun/runtimes/nuclio/application/__init__.py,sha256=rRs5vasy_G9IyoTpYIjYDafGoL6ifFBKgBtsXn31Atw,614
302
- mlrun/runtimes/nuclio/application/application.py,sha256=WxUKsW46rbezvXZp0Q3B9TAa8hP2kcyz2SgOxA-nRYw,19669
302
+ mlrun/runtimes/nuclio/application/application.py,sha256=EO0hY86ZX4XWf7F5mnEX-VTbii1Q_UtVyeoCSEJa0XE,20817
303
303
  mlrun/runtimes/nuclio/application/reverse_proxy.go,sha256=JIIYae6bXzCLf3jXuu49KWPQYoXr_FDQ2Rbo1OWKAd0,3150
304
304
  mlrun/runtimes/sparkjob/__init__.py,sha256=_KPvk0qefeLtHO6lxQE_AMOGiMTG_OT48eRCE4Z2ldw,709
305
305
  mlrun/runtimes/sparkjob/spark3job.py,sha256=1bNRy72Migrh_ZASQOx7UlSZTbB-xpNc76sz4kfc9UM,41191
@@ -307,9 +307,9 @@ mlrun/serving/__init__.py,sha256=-SMRV3q_5cGVPDxRslXPU0zGYZIygs0cSj7WKlOJJUc,116
307
307
  mlrun/serving/merger.py,sha256=PXLn3A21FiLteJHaDSLm5xKNT-80eTTjfHUJnBX1gKY,6116
308
308
  mlrun/serving/remote.py,sha256=MrFByphQWmIsKXqw-MOwl2Q1hbtWReYVRKvlcKj9pfw,17980
309
309
  mlrun/serving/routers.py,sha256=tjTAiLkV-BcRnUfbTqfrKB0j2LMTMygG_2oV_eQ26bs,55470
310
- mlrun/serving/server.py,sha256=M4FITzvSB6JLHes9BasdUXqNDK1CG8mVpxR3pXYXjHg,21433
310
+ mlrun/serving/server.py,sha256=LUf38ArOvs1cUbqxr3ZT015DTr4G5GIlToRaKqbhamc,21512
311
311
  mlrun/serving/serving_wrapper.py,sha256=R670-S6PX_d5ER6jiHtRvacuPyFzQH0mEf2K0sBIIOM,836
312
- mlrun/serving/states.py,sha256=XA9GJB9JZNcaywCGJ1DLxHoS225J3aF8s8B8Y_-bKM8,59341
312
+ mlrun/serving/states.py,sha256=VuRqrZG-Vhhy8Nfi0IiYG2Adn4kAIDZsWgRDfcOKibo,59641
313
313
  mlrun/serving/utils.py,sha256=lej7XcUPX1MmHkEOi_0KZRGSpfbmpnE0GK_Sn4zLkHY,4025
314
314
  mlrun/serving/v1_serving.py,sha256=by4myxlnwyZ0ijQ5fURilGCK1sUpdQL2Il1VR3Xqpxg,11805
315
315
  mlrun/serving/v2_serving.py,sha256=ARsAU0xaQqZoYWdtTLauMPlIX33Nus-BFQOTPZBYda8,24496
@@ -323,8 +323,8 @@ mlrun/utils/async_http.py,sha256=CZY8hNBMQaWrT6PLplyocCFbzaKrJnknFUP0e6kcDBw,117
323
323
  mlrun/utils/azure_vault.py,sha256=IEFizrDGDbAaoWwDr1WoA88S_EZ0T--vjYtY-i0cvYQ,3450
324
324
  mlrun/utils/clones.py,sha256=mJpx4nyFiY6jlBCvFABsNuyi_mr1mvfPWn81vlafpOU,7361
325
325
  mlrun/utils/condition_evaluator.py,sha256=-nGfRmZzivn01rHTroiGY4rqEv8T1irMyhzxEei-sKc,1897
326
- mlrun/utils/db.py,sha256=KEa-vzicUhzIwo1wBXax2ZuXtYgf5to7wnsY3CYCiOQ,1713
327
- mlrun/utils/helpers.py,sha256=Pl1LzfuDVzpQtDC23VFvnuWY8UHs-o7zcYcpNcSF3To,56976
326
+ mlrun/utils/db.py,sha256=2TydIZzJJs9Rf8Qid6ze-Odb1HIzSPAT-Jr-HuHAris,1863
327
+ mlrun/utils/helpers.py,sha256=TUADKuE5d9jDpjiykNbQ9fV2G3e0StaZIsAcIX12VoI,56948
328
328
  mlrun/utils/http.py,sha256=l_JCPrCq8bfYUcUcAFWUPvb9Xu-93bLGIhV-H-XCU9s,8707
329
329
  mlrun/utils/logger.py,sha256=cag2J30-jynIHmHZ2J8RYmVMNhYBGgAoimc5sbk-A1U,10016
330
330
  mlrun/utils/regex.py,sha256=b0AUa2THS-ELzJj0grl5b8Stq609F2XomTZkD9SB1fQ,4900
@@ -340,13 +340,13 @@ mlrun/utils/notifications/notification/console.py,sha256=MAVk7v5PJ52vdGRv76YcEPi
340
340
  mlrun/utils/notifications/notification/git.py,sha256=g_8RksjCboGrKKjyhkePk5nSWrfdT61JkhMeg9EeGcY,6119
341
341
  mlrun/utils/notifications/notification/ipython.py,sha256=ZtVL30B_Ha0VGoo4LxO-voT1U41IYwyytovv5X_LsI4,2066
342
342
  mlrun/utils/notifications/notification/slack.py,sha256=wqpFGr5BTvFO5KuUSzFfxsgmyU1Ohq7fbrGeNe9TXOk,7006
343
- mlrun/utils/notifications/notification/webhook.py,sha256=y8Hc3rlR48M2W76lfI2knEBxlD_T6k9P9kXD_vqFnfg,4472
343
+ mlrun/utils/notifications/notification/webhook.py,sha256=cb9w1Mc8ENfJBdgan7iiVHK9eVls4-R3tUxmXM-P-8I,4746
344
344
  mlrun/utils/version/__init__.py,sha256=7kkrB7hEZ3cLXoWj1kPoDwo4MaswsI2JVOBpbKgPAgc,614
345
- mlrun/utils/version/version.json,sha256=bF07SUc3kt0cxWLc2toAHKMH3fldu-Xj7OtOTIRrx44,89
345
+ mlrun/utils/version/version.json,sha256=zEtEwyoNa009X90xhQ4jFOfgdeXH8KwRfsHjXy_i7-I,89
346
346
  mlrun/utils/version/version.py,sha256=eEW0tqIAkU9Xifxv8Z9_qsYnNhn3YH7NRAfM-pPLt1g,1878
347
- mlrun-1.7.0rc33.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
348
- mlrun-1.7.0rc33.dist-info/METADATA,sha256=_hmgPc5EaCBTVPlT9ULORtjuNezfTWuFa5_fK8uGiiM,19534
349
- mlrun-1.7.0rc33.dist-info/WHEEL,sha256=Wyh-_nZ0DJYolHNn1_hMa4lM7uDedD_RGVwbmTjyItk,91
350
- mlrun-1.7.0rc33.dist-info/entry_points.txt,sha256=1Owd16eAclD5pfRCoJpYC2ZJSyGNTtUr0nCELMioMmU,46
351
- mlrun-1.7.0rc33.dist-info/top_level.txt,sha256=NObLzw3maSF9wVrgSeYBv-fgnHkAJ1kEkh12DLdd5KM,6
352
- mlrun-1.7.0rc33.dist-info/RECORD,,
347
+ mlrun-1.7.0rc34.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
348
+ mlrun-1.7.0rc34.dist-info/METADATA,sha256=nAG6_6ocnS0VmLAyKlqb_EiEAGlCqylo-aMGixGAB8o,19534
349
+ mlrun-1.7.0rc34.dist-info/WHEEL,sha256=Wyh-_nZ0DJYolHNn1_hMa4lM7uDedD_RGVwbmTjyItk,91
350
+ mlrun-1.7.0rc34.dist-info/entry_points.txt,sha256=1Owd16eAclD5pfRCoJpYC2ZJSyGNTtUr0nCELMioMmU,46
351
+ mlrun-1.7.0rc34.dist-info/top_level.txt,sha256=NObLzw3maSF9wVrgSeYBv-fgnHkAJ1kEkh12DLdd5KM,6
352
+ mlrun-1.7.0rc34.dist-info/RECORD,,