mlrun 1.8.0rc15__py3-none-any.whl → 1.8.0rc17__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.

@@ -47,6 +47,7 @@ class DocumentLoaderSpec(ModelObj):
47
47
  self,
48
48
  loader_class_name: str = "langchain_community.document_loaders.TextLoader",
49
49
  src_name: str = "file_path",
50
+ download_object: bool = False,
50
51
  kwargs: Optional[dict] = None,
51
52
  ):
52
53
  """
@@ -56,7 +57,9 @@ class DocumentLoaderSpec(ModelObj):
56
57
  loader_class_name (str): The name of the loader class to use.
57
58
  src_name (str): The source name for the document.
58
59
  kwargs (Optional[dict]): Additional keyword arguments to pass to the loader class.
59
-
60
+ download_object (bool, optional): If True, the file will be downloaded before launching
61
+ the loader. If False, the loader accepts a link that should not be downloaded.
62
+ Defaults to False.
60
63
  Example:
61
64
  >>> # Create a loader specification for PDF documents
62
65
  >>> loader_spec = DocumentLoaderSpec(
@@ -72,6 +75,7 @@ class DocumentLoaderSpec(ModelObj):
72
75
  """
73
76
  self.loader_class_name = loader_class_name
74
77
  self.src_name = src_name
78
+ self.download_object = download_object
75
79
  self.kwargs = kwargs
76
80
 
77
81
  def make_loader(self, src_path):
@@ -251,6 +255,9 @@ class DocumentArtifact(Artifact):
251
255
  "collections",
252
256
  "original_source",
253
257
  ]
258
+ _exclude_fields_from_uid_hash = ArtifactSpec._exclude_fields_from_uid_hash + [
259
+ "collections",
260
+ ]
254
261
 
255
262
  def __init__(
256
263
  self,
@@ -270,7 +277,6 @@ class DocumentArtifact(Artifact):
270
277
  METADATA_SOURCE_KEY = "source"
271
278
  METADATA_ORIGINAL_SOURCE_KEY = "original_source"
272
279
  METADATA_CHUNK_KEY = "mlrun_chunk"
273
- METADATA_ARTIFACT_URI_KEY = "mlrun_object_uri"
274
280
  METADATA_ARTIFACT_TARGET_PATH_KEY = "mlrun_target_path"
275
281
  METADATA_ARTIFACT_TAG = "mlrun_tag"
276
282
  METADATA_ARTIFACT_KEY = "mlrun_key"
@@ -321,7 +327,7 @@ class DocumentArtifact(Artifact):
321
327
  """
322
328
 
323
329
  loader_spec = DocumentLoaderSpec.from_dict(self.spec.document_loader)
324
- if self.get_target_path():
330
+ if loader_spec.download_object and self.get_target_path():
325
331
  with tempfile.NamedTemporaryFile() as tmp_file:
326
332
  mlrun.datastore.store_manager.object(
327
333
  url=self.get_target_path()
@@ -348,7 +354,6 @@ class DocumentArtifact(Artifact):
348
354
 
349
355
  metadata[self.METADATA_ORIGINAL_SOURCE_KEY] = self.spec.original_source
350
356
  metadata[self.METADATA_SOURCE_KEY] = self.get_source()
351
- metadata[self.METADATA_ARTIFACT_URI_KEY] = self.uri
352
357
  metadata[self.METADATA_ARTIFACT_TAG] = self.tag or "latest"
353
358
  metadata[self.METADATA_ARTIFACT_KEY] = self.key
354
359
  metadata[self.METADATA_ARTIFACT_PROJECT] = self.metadata.project
@@ -38,12 +38,10 @@ def parse_model_endpoint_store_prefix(store_prefix: str):
38
38
 
39
39
  def parse_monitoring_stream_path(
40
40
  stream_uri: str, project: str, function_name: typing.Optional[str] = None
41
- ):
41
+ ) -> str:
42
42
  if stream_uri.startswith("kafka://"):
43
43
  if "?topic" in stream_uri:
44
- raise mlrun.errors.MLRunInvalidArgumentError(
45
- "Custom kafka topic is not allowed"
46
- )
44
+ raise mlrun.errors.MLRunValueError("Custom kafka topic is not allowed")
47
45
  # Add topic to stream kafka uri
48
46
  if (
49
47
  function_name is None
@@ -53,22 +51,6 @@ def parse_monitoring_stream_path(
53
51
  else:
54
52
  stream_uri += f"?topic=monitoring_stream_{project}_{function_name}"
55
53
 
56
- elif stream_uri.startswith("v3io://") and mlrun.mlconf.is_ce_mode():
57
- # V3IO is not supported in CE mode, generating a default http stream path
58
- if function_name is None:
59
- stream_uri = (
60
- mlrun.mlconf.model_endpoint_monitoring.default_http_sink.format(
61
- project=project, namespace=mlrun.mlconf.namespace
62
- )
63
- )
64
- else:
65
- stream_uri = (
66
- mlrun.mlconf.model_endpoint_monitoring.default_http_sink_app.format(
67
- project=project,
68
- application_name=function_name,
69
- namespace=mlrun.mlconf.namespace,
70
- )
71
- )
72
54
  return stream_uri
73
55
 
74
56
 
@@ -66,3 +66,4 @@ class ClientSpec(pydantic.v1.BaseModel):
66
66
  packagers: typing.Optional[dict]
67
67
  external_platform_tracking: typing.Optional[dict]
68
68
  alerts_mode: typing.Optional[str]
69
+ system_id: typing.Optional[str]
@@ -75,6 +75,7 @@ class ModelEndpointCreationStrategy(MonitoringStrEnum):
75
75
  INPLACE = "inplace"
76
76
  ARCHIVE = "archive"
77
77
  OVERWRITE = "overwrite"
78
+ SKIP = "skip"
78
79
 
79
80
 
80
81
  class EventFieldType:
@@ -236,6 +237,8 @@ class ProjectSecretKeys:
236
237
  ACCESS_KEY = "MODEL_MONITORING_ACCESS_KEY"
237
238
  STREAM_PATH = "STREAM_PATH"
238
239
  TSDB_CONNECTION = "TSDB_CONNECTION"
240
+ TSDB_PROFILE_NAME = "TSDB_PROFILE_NAME"
241
+ STREAM_PROFILE_NAME = "STREAM_PROFILE_NAME"
239
242
 
240
243
  @classmethod
241
244
  def mandatory_secrets(cls):
mlrun/config.py CHANGED
@@ -603,10 +603,6 @@ default_config = {
603
603
  # Offline storage path can be either relative or a full path. This path is used for general offline data
604
604
  # storage such as the parquet file which is generated from the monitoring stream function for the drift analysis
605
605
  "offline_storage_path": "model-endpoints/{kind}",
606
- # Default http path that points to the monitoring stream nuclio function. Will be used as a stream path
607
- # when the user is working in CE environment and has not provided any stream path.
608
- "default_http_sink": "http://nuclio-{project}-model-monitoring-stream.{namespace}.svc.cluster.local:8080",
609
- "default_http_sink_app": "http://nuclio-{project}-{application_name}.{namespace}.svc.cluster.local:8080",
610
606
  "parquet_batching_max_events": 10_000,
611
607
  "parquet_batching_timeout_secs": timedelta(minutes=1).total_seconds(),
612
608
  # See mlrun.model_monitoring.db.tsdb.ObjectTSDBFactory for available options
@@ -11,7 +11,7 @@
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
+
15
15
  import ast
16
16
  import base64
17
17
  import json
@@ -549,6 +549,35 @@ class DatastoreProfile2Json(pydantic.v1.BaseModel):
549
549
 
550
550
 
551
551
  def datastore_profile_read(url, project_name="", secrets: typing.Optional[dict] = None):
552
+ """
553
+ Read and retrieve a datastore profile from a given URL.
554
+
555
+ This function retrieves a datastore profile either from temporary client storage,
556
+ or from the MLRun database. It handles both client-side and server-side profile formats
557
+ and performs necessary conversions.
558
+
559
+ Args:
560
+ url (str): A URL with 'ds' scheme pointing to the datastore profile
561
+ (e.g., 'ds://profile-name').
562
+ project_name (str, optional): The project name where the profile is stored.
563
+ Defaults to MLRun's default project.
564
+ secrets (dict, optional): Dictionary containing secrets needed for profile retrieval.
565
+
566
+ Returns:
567
+ DatastoreProfile: The retrieved datastore profile object.
568
+
569
+ Raises:
570
+ MLRunInvalidArgumentError: In the following cases:
571
+ - If the URL scheme is not 'ds'
572
+ - If the profile cannot be retrieved from either server or local environment
573
+
574
+ Note:
575
+ When running from a client environment (outside MLRun pods), private profile information
576
+ is not accessible. In this case, use register_temporary_client_datastore_profile() to
577
+ register the profile with credentials for your local session. When running inside MLRun
578
+ pods, the private information is automatically available and no temporary registration is needed.
579
+ """
580
+
552
581
  parsed_url = urlparse(url)
553
582
  if parsed_url.scheme.lower() != "ds":
554
583
  raise mlrun.errors.MLRunInvalidArgumentError(
@@ -580,7 +609,7 @@ def datastore_profile_read(url, project_name="", secrets: typing.Optional[dict]
580
609
  )
581
610
  private_body = get_secret_or_env(project_ds_name_private, secret_provider=secrets)
582
611
  if not public_profile or not private_body:
583
- raise mlrun.errors.MLRunInvalidArgumentError(
612
+ raise mlrun.errors.MLRunNotFoundError(
584
613
  f"Unable to retrieve the datastore profile '{url}' from either the server or local environment. "
585
614
  "Make sure the profile is registered correctly, or if running in a local environment, "
586
615
  "use register_temporary_client_datastore_profile() to provide credentials locally."
mlrun/db/base.py CHANGED
@@ -1079,7 +1079,7 @@ class RunDBInterface(ABC):
1079
1079
  def set_model_monitoring_credentials(
1080
1080
  self,
1081
1081
  project: str,
1082
- credentials: dict[str, str],
1082
+ credentials: dict[str, Optional[str]],
1083
1083
  replace_creds: bool,
1084
1084
  ) -> None:
1085
1085
  pass
mlrun/db/httpdb.py CHANGED
@@ -580,6 +580,7 @@ class HTTPRunDB(RunDBInterface):
580
580
  or config.feature_store.default_targets
581
581
  )
582
582
  config.alerts.mode = server_cfg.get("alerts_mode") or config.alerts.mode
583
+ config.system_id = server_cfg.get("system_id") or config.system_id
583
584
 
584
585
  except Exception as exc:
585
586
  logger.warning(
@@ -773,7 +774,7 @@ class HTTPRunDB(RunDBInterface):
773
774
 
774
775
  response = self.api_call(
775
776
  "POST",
776
- path=f"projects/{project}/runs/{uid}/push_notifications",
777
+ path=f"projects/{project}/runs/{uid}/push-notifications",
777
778
  error="Failed push notifications",
778
779
  timeout=timeout,
779
780
  )
@@ -4017,7 +4018,7 @@ class HTTPRunDB(RunDBInterface):
4017
4018
  def set_model_monitoring_credentials(
4018
4019
  self,
4019
4020
  project: str,
4020
- credentials: dict[str, str],
4021
+ credentials: dict[str, Optional[str]],
4021
4022
  replace_creds: bool,
4022
4023
  ) -> None:
4023
4024
  """
mlrun/db/nopdb.py CHANGED
@@ -872,7 +872,7 @@ class NopDB(RunDBInterface):
872
872
  def set_model_monitoring_credentials(
873
873
  self,
874
874
  project: str,
875
- credentials: dict[str, str],
875
+ credentials: dict[str, Optional[str]],
876
876
  replace_creds: bool,
877
877
  ) -> None:
878
878
  pass
mlrun/execution.py CHANGED
@@ -884,6 +884,7 @@ class MLClientCtx:
884
884
  upload: Optional[bool] = False,
885
885
  labels: Optional[dict[str, str]] = None,
886
886
  target_path: Optional[str] = None,
887
+ db_key: Optional[str] = None,
887
888
  **kwargs,
888
889
  ) -> DocumentArtifact:
889
890
  """
@@ -914,6 +915,8 @@ class MLClientCtx:
914
915
  :param upload: Whether to upload the artifact
915
916
  :param labels: Key-value labels
916
917
  :param target_path: Path to the local file
918
+ :param db_key: The key to use in the artifact DB table, by default its run name + '_' + key
919
+ db_key=False will not register it in the artifacts table
917
920
  :param kwargs: Additional keyword arguments
918
921
  :return: DocumentArtifact object
919
922
 
@@ -943,6 +946,9 @@ class MLClientCtx:
943
946
  tag=tag,
944
947
  upload=upload,
945
948
  labels=labels,
949
+ local_path=local_path,
950
+ target_path=target_path,
951
+ db_key=db_key,
946
952
  )
947
953
  self._update_run()
948
954
  return item
@@ -12,8 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- # for backwards compatibility
16
-
17
15
  from mlrun.common.schemas import ModelEndpoint, ModelEndpointList
18
16
 
19
17
  from .db import get_tsdb_connector
@@ -93,7 +93,7 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
93
93
  context: "mlrun.MLClientCtx",
94
94
  sample_data: Optional[pd.DataFrame] = None,
95
95
  reference_data: Optional[pd.DataFrame] = None,
96
- endpoint_names: Optional[list[str]] = None,
96
+ endpoints: Optional[list[tuple[str, str]]] = None,
97
97
  start: Optional[datetime] = None,
98
98
  end: Optional[datetime] = None,
99
99
  ):
@@ -121,12 +121,13 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
121
121
  )
122
122
  return self.do_tracking(monitoring_context)
123
123
 
124
- if endpoint_names is not None:
124
+ if endpoints is not None:
125
125
  start, end = self._validate_times(start, end)
126
- for endpoint_name in endpoint_names:
126
+ for endpoint_name, endpoint_id in endpoints:
127
127
  result = call_do_tracking(
128
128
  event={
129
129
  mm_constants.ApplicationEvent.ENDPOINT_NAME: endpoint_name,
130
+ mm_constants.ApplicationEvent.ENDPOINT_ID: endpoint_id,
130
131
  mm_constants.ApplicationEvent.START_INFER_TIME: start,
131
132
  mm_constants.ApplicationEvent.END_INFER_TIME: end,
132
133
  }
@@ -199,7 +200,7 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
199
200
  with_repo: Optional[bool] = False,
200
201
  requirements: Optional[Union[str, list[str]]] = None,
201
202
  requirements_file: str = "",
202
- endpoint_names: Optional[list[str]] = None,
203
+ endpoints: Optional[list[tuple[str, str]]] = None,
203
204
  start: Optional[datetime] = None,
204
205
  end: Optional[datetime] = None,
205
206
  ) -> "mlrun.RunObject":
@@ -208,20 +209,23 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
208
209
  :py:meth:`~mlrun.model_monitoring.applications.ModelMonitoringApplicationBase.do_tracking`
209
210
  model monitoring logic as a :py:class:`~mlrun.runtimes.KubejobRuntime`, which is an MLRun function.
210
211
 
211
- :param func_path: The path to the function. If not passed, the current notebook is used.
212
- :param func_name: The name of the function. If not passed, the class name is used.
213
- :param tag: An optional tag for the function.
214
- :param run_local: Whether to run the function locally or remotely.
215
- :param sample_data: Optional - pandas data-frame as the current dataset.
212
+ This method has default values for all of its arguments. You should be change them when you want to pass
213
+ data to the application.
214
+
215
+ :param func_path: The path to the function. If ``None``, the current notebook is used.
216
+ :param func_name: The name of the function. If not ``None``, the class name is used.
217
+ :param tag: Tag for the function.
218
+ :param run_local: Whether to run the function locally or remotely.
219
+ :param sample_data: Pandas data-frame as the current dataset.
216
220
  When set, it replaces the data read from the model endpoint's offline source.
217
- :param reference_data: Optional - pandas data-frame of the reference dataset.
221
+ :param reference_data: Pandas data-frame of the reference dataset.
218
222
  When set, its statistics override the model endpoint's feature statistics.
219
223
  :param image: Docker image to run the job on.
220
224
  :param with_repo: Whether to clone the current repo to the build source.
221
225
  :param requirements: List of Python requirements to be installed in the image.
222
226
  :param requirements_file: Path to a Python requirements file to be installed in the image.
223
- :param endpoint_names: The model endpoint names to get the data from. When the names are passed,
224
- you have to provide also the start and end times of the data to analyze.
227
+ :param endpoints: A list of tuples of the model endpoint (name, uid) to get the data from.
228
+ If provided, you have to provide also the start and end times of the data to analyze.
225
229
  :param start: The start time of the sample data.
226
230
  :param end: The end time of the sample data.
227
231
 
@@ -249,12 +253,16 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
249
253
  ),
250
254
  )
251
255
 
252
- params: dict[str, Union[list[str], datetime]] = {}
253
- if endpoint_names:
256
+ params: dict[str, Union[list[tuple[str, str]], datetime]] = {}
257
+ if endpoints:
254
258
  start, end = cls._validate_times(start, end)
255
- params["endpoint_names"] = endpoint_names
259
+ params["endpoints"] = endpoints
256
260
  params["start"] = start
257
261
  params["end"] = end
262
+ elif start or end:
263
+ raise mlrun.errors.MLRunValueError(
264
+ "Custom start or end times are supported only with endpoints data"
265
+ )
258
266
 
259
267
  inputs: dict[str, str] = {}
260
268
  for data, identifier in [
@@ -190,18 +190,13 @@ class MonitoringApplicationContext:
190
190
  )
191
191
 
192
192
  def _get_default_labels(self) -> dict[str, str]:
193
- labels = {
193
+ return {
194
194
  mlrun_constants.MLRunInternalLabels.runner_pod: socket.gethostname(),
195
195
  mlrun_constants.MLRunInternalLabels.producer_type: "model-monitoring-app",
196
196
  mlrun_constants.MLRunInternalLabels.app_name: self.application_name,
197
+ mlrun_constants.MLRunInternalLabels.endpoint_id: self.endpoint_id,
198
+ mlrun_constants.MLRunInternalLabels.endpoint_name: self.endpoint_name,
197
199
  }
198
- for key, value in [
199
- (mlrun_constants.MLRunInternalLabels.endpoint_id, self.endpoint_id),
200
- (mlrun_constants.MLRunInternalLabels.endpoint_name, self.endpoint_name),
201
- ]:
202
- if value:
203
- labels[key] = value
204
- return labels
205
200
 
206
201
  def _add_default_labels(self, labels: Optional[dict[str, str]]) -> dict[str, str]:
207
202
  """Add the default labels to logged artifacts labels"""
@@ -16,7 +16,9 @@ import enum
16
16
  import typing
17
17
 
18
18
  import mlrun.common.schemas.secret
19
+ import mlrun.datastore.datastore_profile
19
20
  import mlrun.errors
21
+ import mlrun.model_monitoring.helpers
20
22
 
21
23
  from .base import TSDBConnector
22
24
 
@@ -80,6 +82,13 @@ def get_tsdb_connector(
80
82
  or the provided TSDB connection is invalid.
81
83
  """
82
84
 
85
+ try:
86
+ profile = mlrun.model_monitoring.helpers._get_tsdb_profile(
87
+ project=project, secret_provider=secret_provider
88
+ )
89
+ except mlrun.errors.MLRunNotFoundError:
90
+ profile = None
91
+
83
92
  tsdb_connection_string = (
84
93
  tsdb_connection_string
85
94
  or mlrun.model_monitoring.helpers.get_tsdb_connection_string(
@@ -92,6 +101,9 @@ def get_tsdb_connector(
92
101
  kwargs["connection_string"] = tsdb_connection_string
93
102
  elif tsdb_connection_string and tsdb_connection_string == "v3io":
94
103
  tsdb_connector_type = mlrun.common.schemas.model_monitoring.TSDBTarget.V3IO_TSDB
104
+ elif isinstance(profile, mlrun.datastore.datastore_profile.DatastoreProfileV3io):
105
+ tsdb_connector_type = mlrun.common.schemas.model_monitoring.TSDBTarget.V3IO_TSDB
106
+ kwargs["v3io_access_key"] = profile.v3io_access_key
95
107
  else:
96
108
  raise mlrun.errors.MLRunInvalidMMStoreTypeError(
97
109
  "You must provide a valid tsdb store connection by using "
@@ -58,6 +58,7 @@ class V3IOTSDBConnector(TSDBConnector):
58
58
  project: str,
59
59
  container: str = _CONTAINER,
60
60
  v3io_framesd: Optional[str] = None,
61
+ v3io_access_key: str = "",
61
62
  create_table: bool = False,
62
63
  ) -> None:
63
64
  super().__init__(project=project)
@@ -65,6 +66,7 @@ class V3IOTSDBConnector(TSDBConnector):
65
66
  self.container = container
66
67
 
67
68
  self.v3io_framesd = v3io_framesd or mlrun.mlconf.v3io_framesd
69
+ self._v3io_access_key = v3io_access_key
68
70
  self._frames_client: Optional[v3io_frames.client.ClientBase] = None
69
71
  self._init_tables_path()
70
72
  self._create_table = create_table
@@ -72,7 +74,9 @@ class V3IOTSDBConnector(TSDBConnector):
72
74
  @property
73
75
  def frames_client(self) -> v3io_frames.client.ClientBase:
74
76
  if not self._frames_client:
75
- self._frames_client = self._get_v3io_frames_client(self.container)
77
+ self._frames_client = self._get_v3io_frames_client(
78
+ self.container, v3io_access_key=self._v3io_access_key
79
+ )
76
80
  if self._create_table:
77
81
  self.create_tables()
78
82
  return self._frames_client
@@ -564,10 +568,13 @@ class V3IOTSDBConnector(TSDBConnector):
564
568
  return source_directory
565
569
 
566
570
  @staticmethod
567
- def _get_v3io_frames_client(v3io_container: str) -> v3io_frames.client.ClientBase:
571
+ def _get_v3io_frames_client(
572
+ v3io_container: str, v3io_access_key: str = ""
573
+ ) -> v3io_frames.client.ClientBase:
568
574
  return mlrun.utils.v3io_clients.get_frames_client(
569
575
  address=mlrun.mlconf.v3io_framesd,
570
576
  container=v3io_container,
577
+ token=v3io_access_key,
571
578
  )
572
579
 
573
580
  def read_metrics_data(
@@ -13,25 +13,20 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import datetime
16
+ import functools
16
17
  import os
17
- import typing
18
+ from fnmatch import fnmatchcase
19
+ from typing import TYPE_CHECKING, Callable, Optional, TypedDict, cast
18
20
 
19
21
  import numpy as np
20
22
  import pandas as pd
21
23
 
22
- if typing.TYPE_CHECKING:
23
- from mlrun.datastore import DataItem
24
- from mlrun.db.base import RunDBInterface
25
- from mlrun.projects import MlrunProject
26
-
27
- from fnmatch import fnmatchcase
28
- from typing import Optional
29
-
30
24
  import mlrun
31
25
  import mlrun.artifacts
32
26
  import mlrun.common.model_monitoring.helpers
33
27
  import mlrun.common.schemas.model_monitoring.constants as mm_constants
34
28
  import mlrun.data_types.infer
29
+ import mlrun.datastore.datastore_profile
35
30
  import mlrun.model_monitoring
36
31
  import mlrun.utils.helpers
37
32
  from mlrun.common.schemas import ModelEndpoint
@@ -41,8 +36,13 @@ from mlrun.common.schemas.model_monitoring.model_endpoints import (
41
36
  )
42
37
  from mlrun.utils import logger
43
38
 
39
+ if TYPE_CHECKING:
40
+ from mlrun.datastore import DataItem
41
+ from mlrun.db.base import RunDBInterface
42
+ from mlrun.projects import MlrunProject
43
+
44
44
 
45
- class _BatchDict(typing.TypedDict):
45
+ class _BatchDict(TypedDict):
46
46
  minutes: int
47
47
  hours: int
48
48
  days: int
@@ -115,20 +115,30 @@ def filter_results_by_regex(
115
115
  def get_stream_path(
116
116
  project: str,
117
117
  function_name: str = mm_constants.MonitoringFunctionNames.STREAM,
118
- stream_uri: typing.Optional[str] = None,
118
+ stream_uri: Optional[str] = None,
119
+ secret_provider: Optional[Callable[[str], str]] = None,
119
120
  ) -> str:
120
121
  """
121
122
  Get stream path from the project secret. If wasn't set, take it from the system configurations
122
123
 
123
124
  :param project: Project name.
124
125
  :param function_name: Application name. Default is model_monitoring_stream.
125
- :param stream_uri: Stream URI. If provided, it will be used instead of the one from the project secret.
126
-
126
+ :param stream_uri: Stream URI. If provided, it will be used instead of the one from the project's secret.
127
+ :param secret_provider: Optional secret provider to get the connection string secret.
128
+ If not set, the env vars are used.
127
129
  :return: Monitoring stream path to the relevant application.
128
130
  """
129
131
 
132
+ try:
133
+ profile = _get_stream_profile(project=project, secret_provider=secret_provider)
134
+ except mlrun.errors.MLRunNotFoundError:
135
+ profile = None
136
+
137
+ if isinstance(profile, mlrun.datastore.datastore_profile.DatastoreProfileV3io):
138
+ stream_uri = "v3io"
139
+
130
140
  stream_uri = stream_uri or mlrun.get_secret_or_env(
131
- mm_constants.ProjectSecretKeys.STREAM_PATH
141
+ key=mm_constants.ProjectSecretKeys.STREAM_PATH, secret_provider=secret_provider
132
142
  )
133
143
 
134
144
  if not stream_uri or stream_uri == "v3io":
@@ -230,7 +240,7 @@ def get_monitoring_drift_measures_data(project: str, endpoint_id: str) -> "DataI
230
240
 
231
241
 
232
242
  def get_tsdb_connection_string(
233
- secret_provider: typing.Optional[typing.Callable[[str], str]] = None,
243
+ secret_provider: Optional[Callable[[str], str]] = None,
234
244
  ) -> str:
235
245
  """Get TSDB connection string from the project secret. If wasn't set, take it from the system
236
246
  configurations.
@@ -244,6 +254,40 @@ def get_tsdb_connection_string(
244
254
  )
245
255
 
246
256
 
257
+ def _get_profile(
258
+ project: str,
259
+ secret_provider: Optional[Callable[[str], str]],
260
+ profile_name_key: str,
261
+ ) -> mlrun.datastore.datastore_profile.DatastoreProfile:
262
+ """
263
+ Get the datastore profile from the project name and secret provider, where the profile's name
264
+ is saved as a secret named `profile_name_key`.
265
+
266
+ :param project: The project name.
267
+ :param secret_provider: Secret provider to get the secrets from, or `None` for env vars.
268
+ :param profile_name_key: The profile name key in the secret store.
269
+ :return: Datastore profile.
270
+ """
271
+ profile_name = mlrun.get_secret_or_env(
272
+ key=profile_name_key, secret_provider=secret_provider
273
+ )
274
+ if not profile_name:
275
+ raise mlrun.errors.MLRunNotFoundError(
276
+ f"Not found `{profile_name_key}` profile name"
277
+ )
278
+ return mlrun.datastore.datastore_profile.datastore_profile_read(
279
+ url=f"ds://{profile_name}", project_name=project, secrets=secret_provider
280
+ )
281
+
282
+
283
+ _get_tsdb_profile = functools.partial(
284
+ _get_profile, profile_name_key=mm_constants.ProjectSecretKeys.TSDB_PROFILE_NAME
285
+ )
286
+ _get_stream_profile = functools.partial(
287
+ _get_profile, profile_name_key=mm_constants.ProjectSecretKeys.STREAM_PROFILE_NAME
288
+ )
289
+
290
+
247
291
  def batch_dict2timedelta(batch_dict: _BatchDict) -> datetime.timedelta:
248
292
  """
249
293
  Convert a batch dictionary to timedelta.
@@ -431,7 +475,7 @@ def get_invocations_metric(project: str) -> ModelEndpointMonitoringMetric:
431
475
 
432
476
 
433
477
  def _get_monitoring_schedules_folder_path(project: str) -> str:
434
- return typing.cast(
478
+ return cast(
435
479
  str,
436
480
  mlrun.mlconf.get_model_monitoring_file_target_path(
437
481
  project=project, kind=mm_constants.FileTargetKind.MONITORING_SCHEDULES