mlrun 1.10.0rc18__py3-none-any.whl → 1.10.0rc20__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.

Files changed (38) hide show
  1. mlrun/__init__.py +21 -2
  2. mlrun/common/constants.py +1 -0
  3. mlrun/common/schemas/function.py +10 -0
  4. mlrun/common/schemas/model_monitoring/constants.py +4 -11
  5. mlrun/common/schemas/model_monitoring/model_endpoints.py +2 -0
  6. mlrun/datastore/__init__.py +9 -1
  7. mlrun/datastore/model_provider/huggingface_provider.py +114 -26
  8. mlrun/datastore/model_provider/model_provider.py +144 -70
  9. mlrun/datastore/model_provider/openai_provider.py +95 -37
  10. mlrun/db/base.py +0 -19
  11. mlrun/db/httpdb.py +10 -46
  12. mlrun/db/nopdb.py +0 -10
  13. mlrun/launcher/base.py +13 -6
  14. mlrun/model_monitoring/api.py +43 -22
  15. mlrun/model_monitoring/applications/base.py +1 -1
  16. mlrun/model_monitoring/controller.py +112 -38
  17. mlrun/model_monitoring/db/_schedules.py +13 -9
  18. mlrun/model_monitoring/stream_processing.py +16 -12
  19. mlrun/platforms/__init__.py +3 -2
  20. mlrun/projects/project.py +2 -2
  21. mlrun/run.py +1 -1
  22. mlrun/runtimes/base.py +5 -2
  23. mlrun/runtimes/daskjob.py +1 -0
  24. mlrun/runtimes/nuclio/application/application.py +84 -5
  25. mlrun/runtimes/nuclio/function.py +3 -1
  26. mlrun/serving/server.py +24 -0
  27. mlrun/serving/states.py +80 -30
  28. mlrun/serving/system_steps.py +60 -36
  29. mlrun/utils/helpers.py +37 -13
  30. mlrun/utils/notifications/notification_pusher.py +1 -1
  31. mlrun/utils/version/version.json +2 -2
  32. {mlrun-1.10.0rc18.dist-info → mlrun-1.10.0rc20.dist-info}/METADATA +4 -4
  33. {mlrun-1.10.0rc18.dist-info → mlrun-1.10.0rc20.dist-info}/RECORD +37 -38
  34. mlrun/api/schemas/__init__.py +0 -259
  35. {mlrun-1.10.0rc18.dist-info → mlrun-1.10.0rc20.dist-info}/WHEEL +0 -0
  36. {mlrun-1.10.0rc18.dist-info → mlrun-1.10.0rc20.dist-info}/entry_points.txt +0 -0
  37. {mlrun-1.10.0rc18.dist-info → mlrun-1.10.0rc20.dist-info}/licenses/LICENSE +0 -0
  38. {mlrun-1.10.0rc18.dist-info → mlrun-1.10.0rc20.dist-info}/top_level.txt +0 -0
@@ -11,33 +11,37 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
-
14
+ import collections
15
15
  import concurrent.futures
16
16
  import datetime
17
17
  import json
18
18
  import os
19
19
  import traceback
20
+ import warnings
20
21
  from collections.abc import Iterator
21
22
  from contextlib import AbstractContextManager
22
23
  from types import TracebackType
23
- from typing import Any, NamedTuple, Optional, Union, cast
24
+ from typing import Any, Final, NamedTuple, Optional, Union, cast
24
25
 
25
26
  import nuclio_sdk
27
+ import numpy as np
26
28
  import pandas as pd
27
29
 
28
30
  import mlrun
29
31
  import mlrun.common.schemas.model_monitoring.constants as mm_constants
32
+ import mlrun.feature_store as fstore
30
33
  import mlrun.model_monitoring
31
34
  import mlrun.model_monitoring.db._schedules as schedules
32
35
  import mlrun.model_monitoring.helpers
33
36
  import mlrun.platforms.iguazio
37
+ from mlrun.common.schemas import EndpointType
34
38
  from mlrun.common.schemas.model_monitoring.constants import (
35
39
  ControllerEvent,
36
40
  ControllerEventEndpointPolicy,
37
41
  )
38
42
  from mlrun.errors import err_to_str
39
43
  from mlrun.model_monitoring.helpers import batch_dict2timedelta
40
- from mlrun.utils import logger
44
+ from mlrun.utils import datetime_now, logger
41
45
 
42
46
  _SECONDS_IN_DAY = int(datetime.timedelta(days=1).total_seconds())
43
47
  _SECONDS_IN_MINUTE = 60
@@ -49,14 +53,16 @@ class _Interval(NamedTuple):
49
53
 
50
54
 
51
55
  class _BatchWindow:
56
+ TIMESTAMP_RESOLUTION_MICRO: Final = 1e-6 # 0.000001 seconds or 1 microsecond
57
+
52
58
  def __init__(
53
59
  self,
54
60
  *,
55
61
  schedules_file: schedules.ModelMonitoringSchedulesFileEndpoint,
56
62
  application: str,
57
63
  timedelta_seconds: int,
58
- last_updated: int,
59
- first_request: int,
64
+ last_updated: float,
65
+ first_request: float,
60
66
  endpoint_mode: mm_constants.EndpointMode = mm_constants.EndpointMode.REAL_TIME,
61
67
  ) -> None:
62
68
  """
@@ -73,15 +79,17 @@ class _BatchWindow:
73
79
  self._endpoint_mode = endpoint_mode
74
80
  self._start = self._get_last_analyzed()
75
81
 
76
- def _get_saved_last_analyzed(self) -> Optional[int]:
77
- return cast(int, self._db.get_application_time(self._application))
82
+ def _get_saved_last_analyzed(
83
+ self,
84
+ ) -> Optional[float]:
85
+ return self._db.get_application_time(self._application)
78
86
 
79
- def _update_last_analyzed(self, last_analyzed: int) -> None:
87
+ def _update_last_analyzed(self, last_analyzed: float) -> None:
80
88
  self._db.update_application_time(
81
89
  application=self._application, timestamp=last_analyzed
82
90
  )
83
91
 
84
- def _get_initial_last_analyzed(self) -> int:
92
+ def _get_initial_last_analyzed(self) -> float:
85
93
  if self._endpoint_mode == mm_constants.EndpointMode.BATCH:
86
94
  logger.info(
87
95
  "No last analyzed time was found for this endpoint and application, as this is "
@@ -107,7 +115,7 @@ class _BatchWindow:
107
115
  self._stop - first_period_in_seconds,
108
116
  )
109
117
 
110
- def _get_last_analyzed(self) -> int:
118
+ def _get_last_analyzed(self) -> float:
111
119
  saved_last_analyzed = self._get_saved_last_analyzed()
112
120
  if saved_last_analyzed is not None:
113
121
  if self._endpoint_mode == mm_constants.EndpointMode.BATCH:
@@ -127,13 +135,16 @@ class _BatchWindow:
127
135
  # Iterate timestamp from start until timestamp <= stop - step
128
136
  # so that the last interval will end at (timestamp + step) <= stop.
129
137
  # Add 1 to stop - step to get <= and not <.
130
- for timestamp in range(self._start, self._stop - self._step + 1, self._step):
138
+ for timestamp in np.arange(
139
+ self._start, self._stop - self._step + 1, self._step
140
+ ):
131
141
  entered = True
132
142
  start_time = datetime.datetime.fromtimestamp(
133
143
  timestamp, tz=datetime.timezone.utc
134
144
  )
135
145
  end_time = datetime.datetime.fromtimestamp(
136
- timestamp + self._step, tz=datetime.timezone.utc
146
+ timestamp - self.TIMESTAMP_RESOLUTION_MICRO + self._step,
147
+ tz=datetime.timezone.utc,
137
148
  )
138
149
  yield _Interval(start_time, end_time)
139
150
 
@@ -149,7 +160,7 @@ class _BatchWindow:
149
160
  # If the endpoint is a batch endpoint, we need to update the last analyzed time
150
161
  # to the end of the batch time.
151
162
  if last_analyzed:
152
- if last_analyzed < self._stop:
163
+ if last_analyzed - self.TIMESTAMP_RESOLUTION_MICRO < self._stop:
153
164
  # If the last analyzed time is earlier than the stop time,
154
165
  # yield the final partial interval from last_analyzed to stop
155
166
  yield _Interval(
@@ -223,7 +234,7 @@ class _BatchWindowGenerator(AbstractContextManager):
223
234
  def get_application_list(self) -> set[str]:
224
235
  return self._schedules_file.get_application_list()
225
236
 
226
- def get_min_last_analyzed(self) -> Optional[int]:
237
+ def get_min_last_analyzed(self) -> Optional[float]:
227
238
  return self._schedules_file.get_min_timestamp()
228
239
 
229
240
  @classmethod
@@ -231,22 +242,29 @@ class _BatchWindowGenerator(AbstractContextManager):
231
242
  cls,
232
243
  last_request: datetime.datetime,
233
244
  endpoint_mode: mm_constants.EndpointMode,
234
- ) -> int:
245
+ not_old_batch_endpoint: bool,
246
+ ) -> float:
235
247
  """
236
248
  Get the last updated time of a model endpoint.
237
249
  """
238
250
 
239
251
  if endpoint_mode == mm_constants.EndpointMode.REAL_TIME:
240
- last_updated = int(
241
- last_request.timestamp()
242
- - cast(
243
- float,
244
- mlrun.mlconf.model_endpoint_monitoring.parquet_batching_timeout_secs,
245
- )
252
+ last_updated = last_request.timestamp() - cast(
253
+ float,
254
+ mlrun.mlconf.model_endpoint_monitoring.parquet_batching_timeout_secs,
246
255
  )
256
+ if not not_old_batch_endpoint:
257
+ # If the endpoint does not have a stream, `last_updated` should be
258
+ # the minimum between the current time and the last updated time.
259
+ # This compensates for the bumping mechanism - see
260
+ # `update_model_endpoint_last_request`.
261
+ last_updated = min(datetime_now().timestamp(), last_updated)
262
+ logger.debug(
263
+ "The endpoint does not have a stream", last_updated=last_updated
264
+ )
247
265
 
248
266
  return last_updated
249
- return int(last_request.timestamp())
267
+ return last_request.timestamp()
250
268
 
251
269
  def get_intervals(
252
270
  self,
@@ -255,6 +273,7 @@ class _BatchWindowGenerator(AbstractContextManager):
255
273
  first_request: datetime.datetime,
256
274
  last_request: datetime.datetime,
257
275
  endpoint_mode: mm_constants.EndpointMode,
276
+ not_old_batch_endpoint: bool,
258
277
  ) -> Iterator[_Interval]:
259
278
  """
260
279
  Get the batch window for a specific endpoint and application.
@@ -266,8 +285,10 @@ class _BatchWindowGenerator(AbstractContextManager):
266
285
  schedules_file=self._schedules_file,
267
286
  application=application,
268
287
  timedelta_seconds=self._timedelta,
269
- last_updated=self._get_last_updated_time(last_request, endpoint_mode),
270
- first_request=int(first_request.timestamp()),
288
+ last_updated=self._get_last_updated_time(
289
+ last_request, endpoint_mode, not_old_batch_endpoint
290
+ ),
291
+ first_request=first_request.timestamp(),
271
292
  endpoint_mode=endpoint_mode,
272
293
  )
273
294
  yield from self.batch_window.get_intervals()
@@ -291,6 +312,8 @@ class MonitoringApplicationController:
291
312
  Note that the MonitoringApplicationController object requires access keys along with valid project configurations.
292
313
  """
293
314
 
315
+ _MAX_FEATURE_SET_PER_WORKER = 1000
316
+
294
317
  def __init__(self) -> None:
295
318
  """Initialize Monitoring Application Controller"""
296
319
  self.project = cast(str, mlrun.mlconf.active_project)
@@ -324,6 +347,9 @@ class MonitoringApplicationController:
324
347
  mlrun.platforms.iguazio.KafkaOutputStream,
325
348
  ],
326
349
  ] = {}
350
+ self.feature_sets: collections.OrderedDict[
351
+ str, mlrun.feature_store.FeatureSet
352
+ ] = collections.OrderedDict()
327
353
  self.tsdb_connector = mlrun.model_monitoring.get_tsdb_connector(
328
354
  project=self.project
329
355
  )
@@ -433,15 +459,14 @@ class MonitoringApplicationController:
433
459
  base_period_minutes, current_min_last_analyzed, current_time
434
460
  )
435
461
  and (
436
- int(endpoint.status.last_request.timestamp())
437
- != last_timestamp_sent
462
+ endpoint.status.last_request.timestamp() != last_timestamp_sent
438
463
  or current_min_last_analyzed != last_analyzed_sent
439
464
  )
440
465
  ):
441
466
  # Write to schedule chief file the last_request, min_last_analyzed we pushed event to stream
442
467
  schedules_file.update_endpoint_timestamps(
443
468
  endpoint_uid=endpoint.metadata.uid,
444
- last_request=int(endpoint.status.last_request.timestamp()),
469
+ last_request=endpoint.status.last_request.timestamp(),
445
470
  last_analyzed=current_min_last_analyzed,
446
471
  )
447
472
  return True
@@ -460,13 +485,14 @@ class MonitoringApplicationController:
460
485
  last_request=endpoint.status.last_request,
461
486
  first_request=endpoint.status.first_request,
462
487
  endpoint_type=endpoint.metadata.endpoint_type,
488
+ feature_set_uri=endpoint.spec.monitoring_feature_set_uri,
463
489
  )
464
490
  return False
465
491
 
466
492
  @staticmethod
467
493
  def _should_send_nop_event(
468
494
  base_period_minutes: int,
469
- min_last_analyzed: int,
495
+ min_last_analyzed: float,
470
496
  current_time: datetime.datetime,
471
497
  ):
472
498
  if min_last_analyzed:
@@ -515,7 +541,7 @@ class MonitoringApplicationController:
515
541
  try:
516
542
  project_name = event[ControllerEvent.PROJECT]
517
543
  endpoint_id = event[ControllerEvent.ENDPOINT_ID]
518
-
544
+ not_old_batch_endpoint = True
519
545
  if (
520
546
  event[ControllerEvent.KIND]
521
547
  == mm_constants.ControllerEventKind.BATCH_COMPLETE
@@ -572,6 +598,10 @@ class MonitoringApplicationController:
572
598
 
573
599
  endpoint_mode = mm_constants.EndpointMode.REAL_TIME
574
600
 
601
+ not_old_batch_endpoint = (
602
+ event[ControllerEvent.ENDPOINT_TYPE] != EndpointType.BATCH_EP
603
+ )
604
+
575
605
  logger.info(
576
606
  "Starting to analyze", timestamp=last_stream_timestamp.isoformat()
577
607
  )
@@ -590,16 +620,49 @@ class MonitoringApplicationController:
590
620
  first_request=first_request,
591
621
  last_request=last_stream_timestamp,
592
622
  endpoint_mode=endpoint_mode,
623
+ not_old_batch_endpoint=not_old_batch_endpoint,
593
624
  ):
594
625
  data_in_window = False
595
- # Serving endpoint - get the relevant window data from the TSDB
596
- prediction_metric = self.tsdb_connector.read_predictions(
597
- start=start_infer_time,
598
- end=end_infer_time,
599
- endpoint_id=endpoint_id,
600
- )
601
- if prediction_metric.data:
602
- data_in_window = True
626
+ if not_old_batch_endpoint:
627
+ # Serving endpoint - get the relevant window data from the TSDB
628
+ prediction_metric = self.tsdb_connector.read_predictions(
629
+ start=start_infer_time,
630
+ end=end_infer_time,
631
+ endpoint_id=endpoint_id,
632
+ )
633
+ if prediction_metric.data:
634
+ data_in_window = True
635
+ else:
636
+ # Old batch endpoint - get the relevant window data from the parquet target
637
+ warnings.warn(
638
+ "Analyzing batch model endpoints with real time processing events is "
639
+ "deprecated in 1.10.0 and will be removed in 1.12.0. "
640
+ "Instead, use job-based serving to invoke and analyze offline batch model"
641
+ "endpoints.",
642
+ # TODO: Remove this in 1.12.0
643
+ FutureWarning,
644
+ )
645
+
646
+ if endpoint_id not in self.feature_sets:
647
+ self.feature_sets[endpoint_id] = fstore.get_feature_set(
648
+ event[ControllerEvent.FEATURE_SET_URI]
649
+ )
650
+ self.feature_sets.move_to_end(endpoint_id, last=False)
651
+ if (
652
+ len(self.feature_sets)
653
+ > self._MAX_FEATURE_SET_PER_WORKER
654
+ ):
655
+ self.feature_sets.popitem(last=True)
656
+ m_fs = self.feature_sets.get(endpoint_id)
657
+
658
+ df = m_fs.to_dataframe(
659
+ start_time=start_infer_time,
660
+ end_time=end_infer_time,
661
+ time_column=mm_constants.EventFieldType.TIMESTAMP,
662
+ storage_options=self.storage_options,
663
+ )
664
+ if len(df) > 0:
665
+ data_in_window = True
603
666
 
604
667
  if not data_in_window:
605
668
  logger.info(
@@ -616,7 +679,10 @@ class MonitoringApplicationController:
616
679
  endpoint_id=endpoint_id,
617
680
  )
618
681
  self._push_to_applications(
619
- start_infer_time=start_infer_time,
682
+ start_infer_time=start_infer_time
683
+ - datetime.timedelta(
684
+ batch_window_generator.batch_window.TIMESTAMP_RESOLUTION_MICRO
685
+ ), # We subtract a microsecond to ensure that the apps will retrieve start time data.
620
686
  end_infer_time=end_infer_time,
621
687
  endpoint_id=endpoint_id,
622
688
  endpoint_name=endpoint_name,
@@ -653,6 +719,9 @@ class MonitoringApplicationController:
653
719
  ControllerEvent.ENDPOINT_TYPE: event[
654
720
  ControllerEvent.ENDPOINT_TYPE
655
721
  ],
722
+ ControllerEvent.FEATURE_SET_URI: event[
723
+ ControllerEvent.FEATURE_SET_URI
724
+ ],
656
725
  ControllerEvent.FIRST_REQUEST: event[
657
726
  ControllerEvent.FIRST_REQUEST
658
727
  ],
@@ -842,6 +911,7 @@ class MonitoringApplicationController:
842
911
  sep=" ", timespec="microseconds"
843
912
  ),
844
913
  endpoint_type=endpoint.metadata.endpoint_type,
914
+ feature_set_uri=endpoint.spec.monitoring_feature_set_uri,
845
915
  endpoint_policy=json.dumps(policy),
846
916
  )
847
917
  policy[ControllerEventEndpointPolicy.ENDPOINT_UPDATED] = (
@@ -859,6 +929,7 @@ class MonitoringApplicationController:
859
929
  sep=" ", timespec="microseconds"
860
930
  ),
861
931
  endpoint_type=endpoint.metadata.endpoint_type.value,
932
+ feature_set_uri=endpoint.spec.monitoring_feature_set_uri,
862
933
  endpoint_policy=policy,
863
934
  )
864
935
 
@@ -871,6 +942,7 @@ class MonitoringApplicationController:
871
942
  timestamp: str,
872
943
  first_request: str,
873
944
  endpoint_type: int,
945
+ feature_set_uri: str,
874
946
  endpoint_policy: dict[str, Any],
875
947
  ) -> None:
876
948
  """
@@ -883,6 +955,7 @@ class MonitoringApplicationController:
883
955
  :param endpoint_id: endpoint id string
884
956
  :param endpoint_name: the endpoint name string
885
957
  :param endpoint_type: Enum of the endpoint type
958
+ :param feature_set_uri: the feature set uri string
886
959
  """
887
960
  event = {
888
961
  ControllerEvent.KIND.value: kind,
@@ -892,6 +965,7 @@ class MonitoringApplicationController:
892
965
  ControllerEvent.TIMESTAMP.value: timestamp,
893
966
  ControllerEvent.FIRST_REQUEST.value: first_request,
894
967
  ControllerEvent.ENDPOINT_TYPE.value: endpoint_type,
968
+ ControllerEvent.FEATURE_SET_URI.value: feature_set_uri,
895
969
  ControllerEvent.ENDPOINT_POLICY.value: endpoint_policy,
896
970
  }
897
971
  logger.info(
@@ -162,19 +162,19 @@ class ModelMonitoringSchedulesFileEndpoint(ModelMonitoringSchedulesFileBase):
162
162
  endpoint_id=model_endpoint.metadata.uid,
163
163
  )
164
164
 
165
- def get_application_time(self, application: str) -> Optional[int]:
165
+ def get_application_time(self, application: str) -> Optional[float]:
166
166
  self._check_open_schedules()
167
167
  return self._schedules.get(application)
168
168
 
169
- def update_application_time(self, application: str, timestamp: int) -> None:
169
+ def update_application_time(self, application: str, timestamp: float) -> None:
170
170
  self._check_open_schedules()
171
- self._schedules[application] = timestamp
171
+ self._schedules[application] = float(timestamp)
172
172
 
173
173
  def get_application_list(self) -> set[str]:
174
174
  self._check_open_schedules()
175
175
  return set(self._schedules.keys())
176
176
 
177
- def get_min_timestamp(self) -> Optional[int]:
177
+ def get_min_timestamp(self) -> Optional[float]:
178
178
  self._check_open_schedules()
179
179
  return min(self._schedules.values(), default=None)
180
180
 
@@ -198,7 +198,7 @@ class ModelMonitoringSchedulesFileChief(ModelMonitoringSchedulesFileBase):
198
198
  project=self._project
199
199
  )
200
200
 
201
- def get_endpoint_last_request(self, endpoint_uid: str) -> Optional[int]:
201
+ def get_endpoint_last_request(self, endpoint_uid: str) -> Optional[float]:
202
202
  self._check_open_schedules()
203
203
  if endpoint_uid in self._schedules:
204
204
  return self._schedules[endpoint_uid].get(
@@ -208,15 +208,19 @@ class ModelMonitoringSchedulesFileChief(ModelMonitoringSchedulesFileBase):
208
208
  return None
209
209
 
210
210
  def update_endpoint_timestamps(
211
- self, endpoint_uid: str, last_request: int, last_analyzed: int
211
+ self, endpoint_uid: str, last_request: float, last_analyzed: float
212
212
  ) -> None:
213
213
  self._check_open_schedules()
214
214
  self._schedules[endpoint_uid] = {
215
- schemas.model_monitoring.constants.ScheduleChiefFields.LAST_REQUEST: last_request,
216
- schemas.model_monitoring.constants.ScheduleChiefFields.LAST_ANALYZED: last_analyzed,
215
+ schemas.model_monitoring.constants.ScheduleChiefFields.LAST_REQUEST: float(
216
+ last_request
217
+ ),
218
+ schemas.model_monitoring.constants.ScheduleChiefFields.LAST_ANALYZED: float(
219
+ last_analyzed
220
+ ),
217
221
  }
218
222
 
219
- def get_endpoint_last_analyzed(self, endpoint_uid: str) -> Optional[int]:
223
+ def get_endpoint_last_analyzed(self, endpoint_uid: str) -> Optional[float]:
220
224
  self._check_open_schedules()
221
225
  if endpoint_uid in self._schedules:
222
226
  return self._schedules[endpoint_uid].get(
@@ -396,6 +396,8 @@ class ProcessEndpointEvent(mlrun.feature_store.steps.MapClass):
396
396
  request_id = event.get("request", {}).get("id") or event.get("resp", {}).get(
397
397
  "id"
398
398
  )
399
+ feature_names = event.get("request", {}).get("input_schema")
400
+ labels_names = event.get("resp", {}).get("output_schema")
399
401
  latency = event.get("microsec")
400
402
  features = event.get("request", {}).get("inputs")
401
403
  predictions = event.get("resp", {}).get("outputs")
@@ -496,6 +498,8 @@ class ProcessEndpointEvent(mlrun.feature_store.steps.MapClass):
496
498
  ),
497
499
  EventFieldType.EFFECTIVE_SAMPLE_COUNT: effective_sample_count,
498
500
  EventFieldType.ESTIMATED_PREDICTION_COUNT: estimated_prediction_count,
501
+ EventFieldType.FEATURE_NAMES: feature_names,
502
+ EventFieldType.LABEL_NAMES: labels_names,
499
503
  }
500
504
  )
501
505
 
@@ -602,19 +606,19 @@ class MapFeatureNames(mlrun.feature_store.steps.MapClass):
602
606
  self.endpoint_type = {}
603
607
 
604
608
  def _infer_feature_names_from_data(self, event):
605
- for endpoint_id in self.feature_names:
606
- if len(self.feature_names[endpoint_id]) >= len(
607
- event[EventFieldType.FEATURES]
608
- ):
609
- return self.feature_names[endpoint_id]
609
+ endpoint_id = event[EventFieldType.ENDPOINT_ID]
610
+ if endpoint_id in self.feature_names and len(
611
+ self.feature_names[endpoint_id]
612
+ ) >= len(event[EventFieldType.FEATURES]):
613
+ return self.feature_names[endpoint_id]
610
614
  return None
611
615
 
612
616
  def _infer_label_columns_from_data(self, event):
613
- for endpoint_id in self.label_columns:
614
- if len(self.label_columns[endpoint_id]) >= len(
615
- event[EventFieldType.PREDICTION]
616
- ):
617
- return self.label_columns[endpoint_id]
617
+ endpoint_id = event[EventFieldType.ENDPOINT_ID]
618
+ if endpoint_id in self.label_columns and len(
619
+ self.label_columns[endpoint_id]
620
+ ) >= len(event[EventFieldType.PREDICTION]):
621
+ return self.label_columns[endpoint_id]
618
622
  return None
619
623
 
620
624
  def do(self, event: dict):
@@ -659,7 +663,7 @@ class MapFeatureNames(mlrun.feature_store.steps.MapClass):
659
663
  "Feature names are not initialized, they will be automatically generated",
660
664
  endpoint_id=endpoint_id,
661
665
  )
662
- feature_names = [
666
+ feature_names = event.get(EventFieldType.FEATURE_NAMES) or [
663
667
  f"f{i}" for i, _ in enumerate(event[EventFieldType.FEATURES])
664
668
  ]
665
669
 
@@ -682,7 +686,7 @@ class MapFeatureNames(mlrun.feature_store.steps.MapClass):
682
686
  "label column names are not initialized, they will be automatically generated",
683
687
  endpoint_id=endpoint_id,
684
688
  )
685
- label_columns = [
689
+ label_columns = event.get(EventFieldType.LABEL_NAMES) or [
686
690
  f"p{i}" for i, _ in enumerate(event[EventFieldType.PREDICTION])
687
691
  ]
688
692
  attributes_to_update[EventFieldType.LABEL_NAMES] = label_columns
@@ -25,6 +25,7 @@ from .iguazio import (
25
25
  )
26
26
 
27
27
 
28
+ # TODO: Remove in 1.11.0
28
29
  class _DeprecationHelper:
29
30
  """A helper class to deprecate old schemas"""
30
31
 
@@ -48,12 +49,12 @@ class _DeprecationHelper:
48
49
  def _warn(self):
49
50
  warnings.warn(
50
51
  f"mlrun.platforms.{self._new_target} is deprecated since version {self._version}, "
51
- f"and will be removed in 1.10. Use mlrun.runtimes.mounts.{self._new_target} instead.",
52
+ f"and will be removed in 1.11.0. Use mlrun.runtimes.mounts.{self._new_target} instead.",
52
53
  FutureWarning,
53
54
  )
54
55
 
55
56
 
56
- # TODO: Remove in 1.10
57
+ # TODO: Remove in 1.11.0
57
58
  # For backwards compatibility
58
59
  VolumeMount = _DeprecationHelper("VolumeMount")
59
60
  auto_mount = _DeprecationHelper("auto_mount")
mlrun/projects/project.py CHANGED
@@ -3939,8 +3939,8 @@ class MlrunProject(ModelObj):
3939
3939
  :param start: The start time to filter by.Corresponding to the `created` field.
3940
3940
  :param end: The end time to filter by. Corresponding to the `created` field.
3941
3941
  :param top_level: If true will return only routers and endpoint that are NOT children of any router.
3942
- :param mode: Specifies the mode of the model endpoint. Can be "real-time", "batch", or both if set
3943
- to None.
3942
+ :param mode: Specifies the mode of the model endpoint. Can be "real-time" (0), "batch" (1), or
3943
+ both if set to None.
3944
3944
  :param uids: If passed will return a list `ModelEndpoint` object with uid in uids.
3945
3945
  :param tsdb_metrics: When True, the time series metrics will be added to the output
3946
3946
  of the resulting.
mlrun/run.py CHANGED
@@ -365,7 +365,7 @@ def import_function(url="", secrets=None, db="", project=None, new_name=None):
365
365
  def import_function_to_dict(url, secrets=None):
366
366
  """Load function spec from local/remote YAML file"""
367
367
  obj = get_object(url, secrets)
368
- runtime = yaml.load(obj, Loader=yaml.FullLoader)
368
+ runtime = yaml.safe_load(obj)
369
369
  remote = "://" in url
370
370
 
371
371
  code = get_in(runtime, "spec.build.functionSourceCode")
mlrun/runtimes/base.py CHANGED
@@ -447,14 +447,17 @@ class BaseRuntime(ModelObj):
447
447
  :return: Dictionary with all the variables that could be parsed
448
448
  """
449
449
  runtime_env = {
450
- "MLRUN_ACTIVE_PROJECT": self.metadata.project or config.active_project
450
+ mlrun_constants.MLRUN_ACTIVE_PROJECT: self.metadata.project
451
+ or config.active_project
451
452
  }
452
453
  if runobj:
453
454
  runtime_env["MLRUN_EXEC_CONFIG"] = runobj.to_json(
454
455
  exclude_notifications_params=True
455
456
  )
456
457
  if runobj.metadata.project:
457
- runtime_env["MLRUN_ACTIVE_PROJECT"] = runobj.metadata.project
458
+ runtime_env[mlrun_constants.MLRUN_ACTIVE_PROJECT] = (
459
+ runobj.metadata.project
460
+ )
458
461
  if runobj.spec.verbose:
459
462
  runtime_env["MLRUN_LOG_LEVEL"] = "DEBUG"
460
463
  if config.httpdb.api_url:
mlrun/runtimes/daskjob.py CHANGED
@@ -541,6 +541,7 @@ class DaskCluster(KubejobRuntime):
541
541
  notifications=notifications,
542
542
  returns=returns,
543
543
  state_thresholds=state_thresholds,
544
+ retry=retry,
544
545
  **launcher_kwargs,
545
546
  )
546
547