mlrun 1.8.0rc29__py3-none-any.whl → 1.8.0rc31__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 (50) hide show
  1. mlrun/__init__.py +2 -34
  2. mlrun/api/schemas/__init__.py +1 -6
  3. mlrun/artifacts/document.py +3 -3
  4. mlrun/artifacts/manager.py +1 -0
  5. mlrun/artifacts/model.py +3 -3
  6. mlrun/common/model_monitoring/helpers.py +16 -7
  7. mlrun/common/runtimes/constants.py +5 -0
  8. mlrun/common/schemas/__init__.py +0 -2
  9. mlrun/common/schemas/model_monitoring/__init__.py +0 -2
  10. mlrun/common/schemas/model_monitoring/constants.py +4 -7
  11. mlrun/common/schemas/model_monitoring/grafana.py +17 -11
  12. mlrun/config.py +9 -36
  13. mlrun/datastore/datastore_profile.py +1 -1
  14. mlrun/datastore/sources.py +14 -13
  15. mlrun/datastore/storeytargets.py +20 -3
  16. mlrun/db/httpdb.py +4 -30
  17. mlrun/k8s_utils.py +2 -5
  18. mlrun/launcher/base.py +16 -0
  19. mlrun/model_monitoring/api.py +1 -2
  20. mlrun/model_monitoring/applications/_application_steps.py +23 -37
  21. mlrun/model_monitoring/applications/base.py +55 -40
  22. mlrun/model_monitoring/applications/context.py +0 -3
  23. mlrun/model_monitoring/applications/results.py +16 -16
  24. mlrun/model_monitoring/controller.py +35 -31
  25. mlrun/model_monitoring/db/tsdb/__init__.py +9 -5
  26. mlrun/model_monitoring/db/tsdb/base.py +60 -39
  27. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +122 -53
  28. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +140 -14
  29. mlrun/model_monitoring/helpers.py +124 -16
  30. mlrun/model_monitoring/stream_processing.py +6 -21
  31. mlrun/projects/pipelines.py +11 -3
  32. mlrun/projects/project.py +104 -115
  33. mlrun/run.py +2 -2
  34. mlrun/runtimes/nuclio/function.py +4 -2
  35. mlrun/serving/routers.py +3 -4
  36. mlrun/serving/server.py +10 -8
  37. mlrun/serving/states.py +12 -2
  38. mlrun/serving/v2_serving.py +25 -20
  39. mlrun/utils/async_http.py +32 -19
  40. mlrun/utils/helpers.py +5 -2
  41. mlrun/utils/logger.py +14 -10
  42. mlrun/utils/notifications/notification_pusher.py +25 -0
  43. mlrun/utils/regex.py +1 -0
  44. mlrun/utils/version/version.json +2 -2
  45. {mlrun-1.8.0rc29.dist-info → mlrun-1.8.0rc31.dist-info}/METADATA +4 -4
  46. {mlrun-1.8.0rc29.dist-info → mlrun-1.8.0rc31.dist-info}/RECORD +50 -50
  47. {mlrun-1.8.0rc29.dist-info → mlrun-1.8.0rc31.dist-info}/LICENSE +0 -0
  48. {mlrun-1.8.0rc29.dist-info → mlrun-1.8.0rc31.dist-info}/WHEEL +0 -0
  49. {mlrun-1.8.0rc29.dist-info → mlrun-1.8.0rc31.dist-info}/entry_points.txt +0 -0
  50. {mlrun-1.8.0rc29.dist-info → mlrun-1.8.0rc31.dist-info}/top_level.txt +0 -0
@@ -95,8 +95,8 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
95
95
  sample_data: Optional[pd.DataFrame] = None,
96
96
  reference_data: Optional[pd.DataFrame] = None,
97
97
  endpoints: Optional[list[tuple[str, str]]] = None,
98
- start: Optional[datetime] = None,
99
- end: Optional[datetime] = None,
98
+ start: Optional[str] = None,
99
+ end: Optional[str] = None,
100
100
  base_period: Optional[int] = None,
101
101
  ):
102
102
  """
@@ -124,7 +124,6 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
124
124
  return self.do_tracking(monitoring_context)
125
125
 
126
126
  if endpoints is not None:
127
- start, end = self._validate_times(start, end, base_period)
128
127
  for window_start, window_end in self._window_generator(
129
128
  start, end, base_period
130
129
  ):
@@ -137,43 +136,40 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
137
136
  mm_constants.ApplicationEvent.END_INFER_TIME: window_end,
138
137
  }
139
138
  )
140
- context.log_result(
141
- f"{endpoint_name}_{window_start.isoformat()}_{window_end.isoformat()}",
142
- result,
139
+ result_key = (
140
+ f"{endpoint_name}_{window_start.isoformat()}_{window_end.isoformat()}"
141
+ if window_start and window_end
142
+ else endpoint_name
143
143
  )
144
+ context.log_result(result_key, result)
144
145
  else:
145
146
  return call_do_tracking()
146
147
 
147
- @staticmethod
148
- def _validate_times(
149
- start: Optional[datetime],
150
- end: Optional[datetime],
151
- base_period: Optional[int],
152
- ) -> tuple[datetime, datetime]:
153
- if (start is None) or (end is None):
154
- raise mlrun.errors.MLRunValueError(
155
- "When `endpoint_names` is provided, you must also pass the start and end times"
156
- )
157
- if (base_period is not None) and not (
158
- isinstance(base_period, int) and base_period > 0
159
- ):
160
- raise mlrun.errors.MLRunValueError(
161
- "`base_period` must be a nonnegative integer - the number of minutes in a monitoring window"
162
- )
163
- return start, end
164
-
165
148
  @staticmethod
166
149
  def _window_generator(
167
- start: datetime, end: datetime, base_period: Optional[int]
168
- ) -> Iterator[tuple[datetime, datetime]]:
150
+ start: Optional[str], end: Optional[str], base_period: Optional[int]
151
+ ) -> Iterator[tuple[Optional[datetime], Optional[datetime]]]:
152
+ if start is None or end is None:
153
+ # A single window based on the `sample_data` input - see `_handler`.
154
+ yield None, None
155
+ return
156
+
157
+ start_dt = datetime.fromisoformat(start)
158
+ end_dt = datetime.fromisoformat(end)
159
+
169
160
  if base_period is None:
170
- yield start, end
161
+ yield start_dt, end_dt
171
162
  return
172
163
 
164
+ if not isinstance(base_period, int) or base_period <= 0:
165
+ raise mlrun.errors.MLRunValueError(
166
+ "`base_period` must be a nonnegative integer - the number of minutes in a monitoring window"
167
+ )
168
+
173
169
  window_length = timedelta(minutes=base_period)
174
- current_start_time = start
175
- while current_start_time < end:
176
- current_end_time = min(current_start_time + window_length, end)
170
+ current_start_time = start_dt
171
+ while current_start_time < end_dt:
172
+ current_end_time = min(current_start_time + window_length, end_dt)
177
173
  yield current_start_time, current_end_time
178
174
  current_start_time = current_end_time
179
175
 
@@ -369,13 +365,25 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
369
365
  :param requirements: List of Python requirements to be installed in the image.
370
366
  :param requirements_file: Path to a Python requirements file to be installed in the image.
371
367
  :param endpoints: A list of tuples of the model endpoint (name, uid) to get the data from.
372
- If provided, you have to provide also the start and end times of the data to analyze.
373
- :param start: The start time of the sample data.
374
- :param end: The end time of the sample data.
368
+ If provided, and ``sample_data`` is not, you have to provide also the ``start`` and
369
+ ``end`` times of the data to analyze from the model endpoints.
370
+ :param start: The start time of the endpoint's data, not included.
371
+ If you want the model endpoint's data at ``start`` included, you need to subtract a
372
+ small ``datetime.timedelta`` from it.
373
+ :param end: The end time of the endpoint's data, included.
374
+ Please note: when ``start`` and ``end`` are set, they create a left-open time interval
375
+ ("window") :math:`(\\text{start}, \\text{end}]` that excludes the endpoint's data at
376
+ ``start`` and includes the data at ``end``:
377
+ :math:`\\text{start} < t \\leq \\text{end}`, :math:`t` is the time taken in the
378
+ window's data.
375
379
  :param base_period: The window length in minutes. If ``None``, the whole window from ``start`` to ``end``
376
380
  is taken. If an integer is specified, the application is run from ``start`` to ``end``
377
381
  in ``base_period`` length windows, except for the last window that ends at ``end`` and
378
- therefore may be shorter.
382
+ therefore may be shorter:
383
+ :math:`(\\text{start}, \\text{start} + \\text{base_period}],
384
+ (\\text{start} + \\text{base_period}, \\text{start} + 2\\cdot\\text{base_period}],
385
+ ..., (\\text{start} + m\\cdot\\text{base_period}, \\text{end}]`,
386
+ where :math:`m` is some positive integer.
379
387
 
380
388
  :returns: The output of the
381
389
  :py:meth:`~mlrun.model_monitoring.applications.ModelMonitoringApplicationBase.do_tracking`
@@ -395,16 +403,23 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
395
403
  project=project,
396
404
  )
397
405
 
398
- params: dict[str, Union[list[tuple[str, str]], datetime, int, None]] = {}
406
+ params: dict[str, Union[list[tuple[str, str]], str, int, None]] = {}
399
407
  if endpoints:
400
- start, end = cls._validate_times(start, end, base_period)
401
408
  params["endpoints"] = endpoints
402
- params["start"] = start
403
- params["end"] = end
404
- params["base_period"] = base_period
409
+ if sample_data is None:
410
+ if start is None or end is None:
411
+ raise mlrun.errors.MLRunValueError(
412
+ "`start` and `end` times must be provided when `endpoints` "
413
+ "is provided without `sample_data`"
414
+ )
415
+ params["start"] = (
416
+ start.isoformat() if isinstance(start, datetime) else start
417
+ )
418
+ params["end"] = end.isoformat() if isinstance(end, datetime) else end
419
+ params["base_period"] = base_period
405
420
  elif start or end or base_period:
406
421
  raise mlrun.errors.MLRunValueError(
407
- "Custom start and end times or base_period are supported only with endpoints data"
422
+ "Custom `start` and `end` times or base_period are supported only with endpoints data"
408
423
  )
409
424
 
410
425
  inputs: dict[str, str] = {}
@@ -111,9 +111,6 @@ class MonitoringApplicationContext:
111
111
  self.endpoint_name = cast(
112
112
  str, event.get(mm_constants.ApplicationEvent.ENDPOINT_NAME)
113
113
  )
114
- self.output_stream_uri = cast(
115
- str, event.get(mm_constants.ApplicationEvent.OUTPUT_STREAM_URI)
116
- )
117
114
 
118
115
  self._feature_stats: Optional[FeatureStats] = feature_stats
119
116
  self._sample_df_stats: Optional[FeatureStats] = None
@@ -22,7 +22,7 @@ from pydantic.v1.dataclasses import dataclass
22
22
 
23
23
  import mlrun.common.helpers
24
24
  import mlrun.common.model_monitoring.helpers
25
- import mlrun.common.schemas.model_monitoring.constants as mm_constant
25
+ import mlrun.common.schemas.model_monitoring.constants as mm_constants
26
26
  import mlrun.utils.v3io_clients
27
27
  from mlrun.utils import logger
28
28
 
@@ -33,10 +33,10 @@ class _ModelMonitoringApplicationDataRes(ABC):
33
33
  name: str
34
34
 
35
35
  def __post_init__(self):
36
- pat = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*")
36
+ pat = re.compile(mm_constants.RESULT_NAME_PATTERN)
37
37
  if not re.fullmatch(pat, self.name):
38
38
  raise mlrun.errors.MLRunValueError(
39
- "Attribute name must comply with the regex `[a-zA-Z_][a-zA-Z0-9_]*`"
39
+ f"Attribute name must comply with the regex `{mm_constants.RESULT_NAME_PATTERN}`"
40
40
  )
41
41
 
42
42
  @abstractmethod
@@ -63,8 +63,8 @@ class ModelMonitoringApplicationResult(_ModelMonitoringApplicationDataRes):
63
63
 
64
64
  name: str
65
65
  value: float
66
- kind: mm_constant.ResultKindApp
67
- status: mm_constant.ResultStatusApp
66
+ kind: mm_constants.ResultKindApp
67
+ status: mm_constants.ResultStatusApp
68
68
  extra_data: dict = dataclasses.field(default_factory=dict)
69
69
 
70
70
  def to_dict(self):
@@ -74,11 +74,11 @@ class ModelMonitoringApplicationResult(_ModelMonitoringApplicationDataRes):
74
74
  :returns: (dict) Dictionary representation of the result.
75
75
  """
76
76
  return {
77
- mm_constant.ResultData.RESULT_NAME: self.name,
78
- mm_constant.ResultData.RESULT_VALUE: self.value,
79
- mm_constant.ResultData.RESULT_KIND: self.kind.value,
80
- mm_constant.ResultData.RESULT_STATUS: self.status.value,
81
- mm_constant.ResultData.RESULT_EXTRA_DATA: json.dumps(self.extra_data),
77
+ mm_constants.ResultData.RESULT_NAME: self.name,
78
+ mm_constants.ResultData.RESULT_VALUE: self.value,
79
+ mm_constants.ResultData.RESULT_KIND: self.kind.value,
80
+ mm_constants.ResultData.RESULT_STATUS: self.status.value,
81
+ mm_constants.ResultData.RESULT_EXTRA_DATA: json.dumps(self.extra_data),
82
82
  }
83
83
 
84
84
  @validator("extra_data")
@@ -118,8 +118,8 @@ class ModelMonitoringApplicationMetric(_ModelMonitoringApplicationDataRes):
118
118
  :returns: (dict) Dictionary representation of the result.
119
119
  """
120
120
  return {
121
- mm_constant.MetricData.METRIC_NAME: self.name,
122
- mm_constant.MetricData.METRIC_VALUE: self.value,
121
+ mm_constants.MetricData.METRIC_NAME: self.name,
122
+ mm_constants.MetricData.METRIC_VALUE: self.value,
123
123
  }
124
124
 
125
125
 
@@ -134,7 +134,7 @@ class _ModelMonitoringApplicationStats(_ModelMonitoringApplicationDataRes):
134
134
 
135
135
  """
136
136
 
137
- name: mm_constant.StatsKind
137
+ name: mm_constants.StatsKind
138
138
  timestamp: str
139
139
  stats: dict = dataclasses.field(default_factory=dict)
140
140
 
@@ -145,7 +145,7 @@ class _ModelMonitoringApplicationStats(_ModelMonitoringApplicationDataRes):
145
145
  :returns: (dict) Dictionary representation of the result.
146
146
  """
147
147
  return {
148
- mm_constant.StatsData.STATS_NAME: self.name,
149
- mm_constant.StatsData.STATS: self.stats,
150
- mm_constant.StatsData.TIMESTAMP: self.timestamp,
148
+ mm_constants.StatsData.STATS_NAME: self.name,
149
+ mm_constants.StatsData.STATS: self.stats,
150
+ mm_constants.StatsData.TIMESTAMP: self.timestamp,
151
151
  }
@@ -27,15 +27,15 @@ import mlrun
27
27
  import mlrun.common.schemas.model_monitoring.constants as mm_constants
28
28
  import mlrun.feature_store as fstore
29
29
  import mlrun.model_monitoring
30
+ import mlrun.model_monitoring.helpers
30
31
  from mlrun.common.schemas import EndpointType
31
32
  from mlrun.common.schemas.model_monitoring.constants import (
32
33
  ControllerEvent,
33
34
  ControllerEventKind,
34
35
  )
35
- from mlrun.datastore import get_stream_pusher
36
36
  from mlrun.errors import err_to_str
37
37
  from mlrun.model_monitoring.db._schedules import ModelMonitoringSchedulesFile
38
- from mlrun.model_monitoring.helpers import batch_dict2timedelta, get_stream_path
38
+ from mlrun.model_monitoring.helpers import batch_dict2timedelta
39
39
  from mlrun.utils import datetime_now, logger
40
40
 
41
41
  _SECONDS_IN_DAY = int(datetime.timedelta(days=1).total_seconds())
@@ -249,10 +249,11 @@ class MonitoringApplicationController:
249
249
  self._window_length = _get_window_length()
250
250
 
251
251
  self.model_monitoring_access_key = self._get_model_monitoring_access_key()
252
- self.v3io_access_key = mlrun.get_secret_or_env("V3IO_ACCESS_KEY")
253
- self.storage_options = None
254
- if mlrun.mlconf.artifact_path.startswith("s3://"):
255
- self.storage_options = mlrun.mlconf.get_s3_storage_options()
252
+ self.v3io_access_key = mlrun.mlconf.get_v3io_access_key()
253
+ store, _, _ = mlrun.store_manager.get_or_create_store(
254
+ mlrun.mlconf.artifact_path
255
+ )
256
+ self.storage_options = store.get_storage_options()
256
257
 
257
258
  @staticmethod
258
259
  def _get_model_monitoring_access_key() -> Optional[str]:
@@ -482,24 +483,23 @@ class MonitoringApplicationController:
482
483
  ),
483
484
  mm_constants.ApplicationEvent.ENDPOINT_ID: endpoint_id,
484
485
  mm_constants.ApplicationEvent.ENDPOINT_NAME: endpoint_name,
485
- mm_constants.ApplicationEvent.OUTPUT_STREAM_URI: get_stream_path(
486
- project=project,
487
- function_name=mm_constants.MonitoringFunctionNames.WRITER,
488
- ),
489
486
  }
490
487
  for app_name in applications_names:
491
488
  data.update({mm_constants.ApplicationEvent.APPLICATION_NAME: app_name})
492
- stream_uri = get_stream_path(project=project, function_name=app_name)
489
+
490
+ app_stream = mlrun.model_monitoring.helpers.get_output_stream(
491
+ project=project,
492
+ function_name=app_name,
493
+ v3io_access_key=model_monitoring_access_key,
494
+ )
493
495
 
494
496
  logger.info(
495
497
  "Pushing data to application stream",
496
498
  endpoint_id=endpoint_id,
497
499
  app_name=app_name,
498
- stream_uri=stream_uri,
499
- )
500
- get_stream_pusher(stream_uri, access_key=model_monitoring_access_key).push(
501
- [data]
500
+ app_stream_type=str(type(app_stream)),
502
501
  )
502
+ app_stream.push([data])
503
503
 
504
504
  def push_regular_event_to_controller_stream(self) -> None:
505
505
  """
@@ -628,10 +628,6 @@ class MonitoringApplicationController:
628
628
  :param feature_set_uri: the feature set uri string
629
629
  :param stream_access_key: access key to apply the model monitoring process.
630
630
  """
631
- stream_uri = get_stream_path(
632
- project=project,
633
- function_name=mm_constants.MonitoringFunctionNames.APPLICATION_CONTROLLER,
634
- )
635
631
  event = {
636
632
  ControllerEvent.KIND.value: kind,
637
633
  ControllerEvent.PROJECT.value: project,
@@ -643,15 +639,18 @@ class MonitoringApplicationController:
643
639
  ControllerEvent.FEATURE_SET_URI.value: feature_set_uri,
644
640
  ControllerEvent.ENDPOINT_POLICY.value: endpoint_policy,
645
641
  }
642
+ controller_stream = mlrun.model_monitoring.helpers.get_output_stream(
643
+ project=project,
644
+ function_name=mm_constants.MonitoringFunctionNames.APPLICATION_CONTROLLER,
645
+ v3io_access_key=stream_access_key,
646
+ )
646
647
  logger.info(
647
648
  "Pushing data to controller stream",
648
649
  event=event,
649
650
  endpoint_id=endpoint_id,
650
- stream_uri=stream_uri,
651
- )
652
- get_stream_pusher(stream_uri, access_key=stream_access_key).push(
653
- [event], partition_key=endpoint_id
651
+ controller_stream_type=str(type(controller_stream)),
654
652
  )
653
+ controller_stream.push([event], partition_key=endpoint_id)
655
654
 
656
655
  def _push_to_main_stream(self, event: dict, endpoint_id: str) -> None:
657
656
  """
@@ -659,17 +658,18 @@ class MonitoringApplicationController:
659
658
  :param event: event dictionary to push to stream
660
659
  :param endpoint_id: endpoint id string
661
660
  """
662
- stream_uri = get_stream_path(project=event.get(ControllerEvent.PROJECT))
663
-
661
+ mm_stream = mlrun.model_monitoring.helpers.get_output_stream(
662
+ project=event.get(ControllerEvent.PROJECT),
663
+ function_name=mm_constants.MonitoringFunctionNames.APPLICATION_CONTROLLER,
664
+ v3io_access_key=self.v3io_access_key,
665
+ )
664
666
  logger.info(
665
667
  "Pushing data to main stream, NOP event is been generated",
666
668
  event=json.dumps(event),
667
669
  endpoint_id=endpoint_id,
668
- stream_uri=stream_uri,
669
- )
670
- get_stream_pusher(stream_uri, access_key=self.model_monitoring_access_key).push(
671
- [event], partition_key=endpoint_id
670
+ mm_stream_type=str(type(mm_stream)),
672
671
  )
672
+ mm_stream.push([event], partition_key=endpoint_id)
673
673
 
674
674
 
675
675
  def handler(context: nuclio_sdk.Context, event: nuclio_sdk.Event) -> None:
@@ -685,12 +685,16 @@ def handler(context: nuclio_sdk.Context, event: nuclio_sdk.Event) -> None:
685
685
  trigger_kind=event.trigger.kind,
686
686
  )
687
687
 
688
- if event.trigger.kind == "http":
688
+ if event.trigger.kind in mm_constants.CRON_TRIGGER_KINDS:
689
689
  # Runs controller chief:
690
690
  context.user_data.monitor_app_controller.push_regular_event_to_controller_stream()
691
- else:
691
+ elif event.trigger.kind in mm_constants.STREAM_TRIGGER_KINDS:
692
692
  # Runs controller worker:
693
693
  context.user_data.monitor_app_controller.run(event)
694
+ else:
695
+ raise mlrun.errors.MLRunInvalidArgumentError(
696
+ "Wrong trigger kind for model monitoring controller"
697
+ )
694
698
 
695
699
 
696
700
  def init_context(context):
@@ -19,6 +19,7 @@ import mlrun.common.schemas.secret
19
19
  import mlrun.datastore.datastore_profile
20
20
  import mlrun.errors
21
21
  import mlrun.model_monitoring.helpers
22
+ from mlrun.datastore.datastore_profile import DatastoreProfile
22
23
 
23
24
  from .base import TSDBConnector
24
25
 
@@ -29,10 +30,13 @@ class ObjectTSDBFactory(enum.Enum):
29
30
  v3io_tsdb = "v3io-tsdb"
30
31
  tdengine = "tdengine"
31
32
 
32
- def to_tsdb_connector(self, project: str, **kwargs) -> TSDBConnector:
33
+ def to_tsdb_connector(
34
+ self, project: str, profile: DatastoreProfile, **kwargs
35
+ ) -> TSDBConnector:
33
36
  """
34
37
  Return a TSDBConnector object based on the provided enum value.
35
38
  :param project: The name of the project.
39
+ :param profile: Datastore profile containing DSN and credentials for TSDB connection
36
40
  :return: `TSDBConnector` object.
37
41
  """
38
42
 
@@ -51,7 +55,7 @@ class ObjectTSDBFactory(enum.Enum):
51
55
 
52
56
  from .tdengine.tdengine_connector import TDEngineConnector
53
57
 
54
- return TDEngineConnector(project=project, **kwargs)
58
+ return TDEngineConnector(project=project, profile=profile, **kwargs)
55
59
 
56
60
  @classmethod
57
61
  def _missing_(cls, value: typing.Any):
@@ -87,12 +91,10 @@ def get_tsdb_connector(
87
91
  kwargs = {}
88
92
  if isinstance(profile, mlrun.datastore.datastore_profile.DatastoreProfileV3io):
89
93
  tsdb_connector_type = mlrun.common.schemas.model_monitoring.TSDBTarget.V3IO_TSDB
90
- kwargs["v3io_access_key"] = profile.v3io_access_key
91
94
  elif isinstance(
92
95
  profile, mlrun.datastore.datastore_profile.TDEngineDatastoreProfile
93
96
  ):
94
97
  tsdb_connector_type = mlrun.common.schemas.model_monitoring.TSDBTarget.TDEngine
95
- kwargs["connection_string"] = profile.dsn()
96
98
  else:
97
99
  extra_message = (
98
100
  ""
@@ -109,4 +111,6 @@ def get_tsdb_connector(
109
111
  tsdb_connector_factory = ObjectTSDBFactory(tsdb_connector_type)
110
112
 
111
113
  # Convert into TSDB connector object
112
- return tsdb_connector_factory.to_tsdb_connector(project=project, **kwargs)
114
+ return tsdb_connector_factory.to_tsdb_connector(
115
+ project=project, profile=profile, **kwargs
116
+ )