mlrun 1.8.0rc4__py3-none-any.whl → 1.8.0rc7__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 (75) hide show
  1. mlrun/__init__.py +5 -3
  2. mlrun/alerts/alert.py +129 -2
  3. mlrun/artifacts/__init__.py +1 -1
  4. mlrun/artifacts/base.py +12 -1
  5. mlrun/artifacts/document.py +59 -38
  6. mlrun/common/constants.py +1 -0
  7. mlrun/common/model_monitoring/__init__.py +0 -2
  8. mlrun/common/model_monitoring/helpers.py +0 -28
  9. mlrun/common/schemas/__init__.py +2 -4
  10. mlrun/common/schemas/alert.py +80 -1
  11. mlrun/common/schemas/artifact.py +4 -0
  12. mlrun/common/schemas/client_spec.py +0 -1
  13. mlrun/common/schemas/model_monitoring/__init__.py +0 -6
  14. mlrun/common/schemas/model_monitoring/constants.py +11 -9
  15. mlrun/common/schemas/model_monitoring/model_endpoints.py +77 -149
  16. mlrun/common/schemas/notification.py +6 -0
  17. mlrun/common/schemas/project.py +3 -0
  18. mlrun/config.py +2 -3
  19. mlrun/datastore/datastore_profile.py +57 -17
  20. mlrun/datastore/sources.py +1 -2
  21. mlrun/datastore/vectorstore.py +67 -59
  22. mlrun/db/base.py +29 -19
  23. mlrun/db/factory.py +0 -3
  24. mlrun/db/httpdb.py +224 -161
  25. mlrun/db/nopdb.py +36 -17
  26. mlrun/execution.py +46 -32
  27. mlrun/feature_store/api.py +1 -0
  28. mlrun/model.py +7 -0
  29. mlrun/model_monitoring/__init__.py +3 -2
  30. mlrun/model_monitoring/api.py +55 -53
  31. mlrun/model_monitoring/applications/_application_steps.py +4 -2
  32. mlrun/model_monitoring/applications/base.py +165 -6
  33. mlrun/model_monitoring/applications/context.py +88 -37
  34. mlrun/model_monitoring/applications/evidently_base.py +0 -1
  35. mlrun/model_monitoring/applications/histogram_data_drift.py +3 -7
  36. mlrun/model_monitoring/controller.py +43 -37
  37. mlrun/model_monitoring/db/__init__.py +0 -2
  38. mlrun/model_monitoring/db/tsdb/base.py +2 -1
  39. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +2 -1
  40. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +43 -0
  41. mlrun/model_monitoring/helpers.py +79 -66
  42. mlrun/model_monitoring/stream_processing.py +83 -270
  43. mlrun/model_monitoring/writer.py +1 -10
  44. mlrun/projects/pipelines.py +37 -1
  45. mlrun/projects/project.py +171 -74
  46. mlrun/run.py +40 -0
  47. mlrun/runtimes/nuclio/function.py +7 -6
  48. mlrun/runtimes/nuclio/serving.py +9 -2
  49. mlrun/serving/routers.py +158 -145
  50. mlrun/serving/server.py +6 -0
  51. mlrun/serving/states.py +21 -7
  52. mlrun/serving/v2_serving.py +70 -61
  53. mlrun/utils/helpers.py +14 -30
  54. mlrun/utils/notifications/notification/mail.py +36 -9
  55. mlrun/utils/notifications/notification_pusher.py +43 -18
  56. mlrun/utils/version/version.json +2 -2
  57. {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/METADATA +5 -4
  58. {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/RECORD +62 -75
  59. mlrun/common/schemas/model_monitoring/model_endpoint_v2.py +0 -149
  60. mlrun/model_monitoring/db/stores/__init__.py +0 -136
  61. mlrun/model_monitoring/db/stores/base/__init__.py +0 -15
  62. mlrun/model_monitoring/db/stores/base/store.py +0 -154
  63. mlrun/model_monitoring/db/stores/sqldb/__init__.py +0 -13
  64. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -46
  65. mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -93
  66. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +0 -47
  67. mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -25
  68. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +0 -408
  69. mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +0 -13
  70. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +0 -464
  71. mlrun/model_monitoring/model_endpoint.py +0 -120
  72. {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/LICENSE +0 -0
  73. {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/WHEEL +0 -0
  74. {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/entry_points.txt +0 -0
  75. {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/top_level.txt +0 -0
@@ -12,9 +12,18 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ import socket
15
16
  from abc import ABC, abstractmethod
16
- from typing import Any, Union
17
+ from datetime import datetime
18
+ from typing import Any, Optional, Union, cast
17
19
 
20
+ import pandas as pd
21
+
22
+ import mlrun
23
+ import mlrun.common.constants as mlrun_constants
24
+ import mlrun.common.schemas.model_monitoring.constants as mm_constants
25
+ import mlrun.errors
26
+ import mlrun.model_monitoring.api as mm_api
18
27
  import mlrun.model_monitoring.applications.context as mm_context
19
28
  import mlrun.model_monitoring.applications.results as mm_results
20
29
  from mlrun.serving.utils import MonitoringApplicationToDict
@@ -22,12 +31,12 @@ from mlrun.serving.utils import MonitoringApplicationToDict
22
31
 
23
32
  class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
24
33
  """
25
- A base class for a model monitoring application.
34
+ The base class for a model monitoring application.
26
35
  Inherit from this class to create a custom model monitoring application.
27
36
 
28
- example for very simple custom application::
37
+ For example, :code:`MyApp` below is a simplistic custom application::
29
38
 
30
- class MyApp(ApplicationBase):
39
+ class MyApp(ModelMonitoringApplicationBase):
31
40
  def do_tracking(
32
41
  self,
33
42
  monitoring_context: mm_context.MonitoringApplicationContext,
@@ -43,8 +52,6 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
43
52
  kind=mm_constant.ResultKindApp.data_drift,
44
53
  status=mm_constant.ResultStatusApp.detected,
45
54
  )
46
-
47
-
48
55
  """
49
56
 
50
57
  kind = "monitoring_application"
@@ -62,6 +69,7 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
62
69
  ]:
63
70
  """
64
71
  Process the monitoring event and return application results & metrics.
72
+ Note: this method is internal and should not be called directly or overridden.
65
73
 
66
74
  :param monitoring_context: (MonitoringApplicationContext) The monitoring application context.
67
75
  :returns: A tuple of:
@@ -80,6 +88,157 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
80
88
  results = results if isinstance(results, list) else [results]
81
89
  return results, monitoring_context
82
90
 
91
+ def _handler(
92
+ self,
93
+ context: "mlrun.MLClientCtx",
94
+ sample_data: Optional[pd.DataFrame] = None,
95
+ reference_data: Optional[pd.DataFrame] = None,
96
+ endpoint_names: Optional[list[str]] = None,
97
+ start: Optional[datetime] = None,
98
+ end: Optional[datetime] = None,
99
+ ):
100
+ """
101
+ A custom handler that wraps the application's logic implemented in
102
+ :py:meth:`~mlrun.model_monitoring.applications.ModelMonitoringApplicationBase.do_tracking`
103
+ for an MLRun job.
104
+ This method should not be called directly.
105
+ """
106
+ feature_stats = (
107
+ mm_api.get_sample_set_statistics(reference_data)
108
+ if reference_data is not None
109
+ else None
110
+ )
111
+
112
+ def call_do_tracking(event: Optional[dict] = None):
113
+ if event is None:
114
+ event = {}
115
+ monitoring_context = mm_context.MonitoringApplicationContext(
116
+ event=event,
117
+ application_name=self.__class__.__name__,
118
+ logger=context.logger,
119
+ artifacts_logger=context,
120
+ sample_df=sample_data,
121
+ feature_stats=feature_stats,
122
+ )
123
+ return self.do_tracking(monitoring_context)
124
+
125
+ if endpoint_names is not None:
126
+ start, end = self._validate_times(start, end)
127
+ for endpoint_name in endpoint_names:
128
+ result = call_do_tracking(
129
+ event={
130
+ mm_constants.ApplicationEvent.ENDPOINT_NAME: endpoint_name,
131
+ mm_constants.ApplicationEvent.START_INFER_TIME: start,
132
+ mm_constants.ApplicationEvent.END_INFER_TIME: end,
133
+ }
134
+ )
135
+ context.log_result(
136
+ f"{endpoint_name}_{start.isoformat()}_{end.isoformat()}", result
137
+ )
138
+ else:
139
+ return call_do_tracking()
140
+
141
+ @staticmethod
142
+ def _validate_times(
143
+ start: Optional[datetime], end: Optional[datetime]
144
+ ) -> tuple[datetime, datetime]:
145
+ if (start is None) or (end is None):
146
+ raise mlrun.errors.MLRunValueError(
147
+ "When `endpoint_names` is provided, you must also pass the start and end times"
148
+ )
149
+ return start, end
150
+
151
+ @classmethod
152
+ def evaluate(
153
+ cls,
154
+ func_path: Optional[str] = None,
155
+ func_name: Optional[str] = None,
156
+ *,
157
+ tag: Optional[str] = None,
158
+ run_local: bool = True,
159
+ sample_data: Optional[pd.DataFrame] = None,
160
+ reference_data: Optional[pd.DataFrame] = None,
161
+ image: Optional[str] = None,
162
+ with_repo: Optional[bool] = False,
163
+ requirements: Optional[Union[str, list[str]]] = None,
164
+ requirements_file: str = "",
165
+ endpoint_names: Optional[list[str]] = None,
166
+ start: Optional[datetime] = None,
167
+ end: Optional[datetime] = None,
168
+ ) -> "mlrun.RunObject":
169
+ """
170
+ Call this function to run the application's
171
+ :py:meth:`~mlrun.model_monitoring.applications.ModelMonitoringApplicationBase.do_tracking`
172
+ model monitoring logic as a :py:class:`~mlrun.runtimes.KubejobRuntime`, which is an MLRun function.
173
+
174
+ :param func_path: The path to the function. If not passed, the current notebook is used.
175
+ :param func_name: The name of the function. If not passed, the class name is used.
176
+ :param tag: An optional tag for the function.
177
+ :param run_local: Whether to run the function locally or remotely.
178
+ :param sample_df: Optional - pandas data-frame as the current dataset.
179
+ When set, it replaces the data read from the model endpoint's offline source.
180
+ :param feature_stats: Optional - statistics dictionary of the reference data.
181
+ When set, it overrides the model endpoint's feature stats.
182
+ :param image: Docker image to run the job on.
183
+ :param with_repo: Whether to clone the current repo to the build source.
184
+ :param requirements: List of Python requirements to be installed in the image.
185
+ :param requirements_file: Path to a Python requirements file to be installed in the image.
186
+ :param endpoint_names: The model endpoint names to get the data from. When the names are passed,
187
+ you have to provide also the start and end times of the data to analyze.
188
+ :param start: The start time of the sample data.
189
+ :param end: The end time of the sample data.
190
+
191
+ :returns: The output of the
192
+ :py:meth:`~mlrun.model_monitoring.applications.ModelMonitoringApplicationBase.do_tracking`
193
+ method with the given parameters and inputs, wrapped in a :py:class:`~mlrun.model.RunObject`.
194
+ """
195
+ project = cast("mlrun.MlrunProject", mlrun.get_current_project())
196
+ class_name = cls.__name__
197
+ job_name = func_name if func_name is not None else class_name
198
+ handler = f"{class_name}::{cls._handler.__name__}"
199
+
200
+ job = cast(
201
+ mlrun.runtimes.KubejobRuntime,
202
+ project.set_function(
203
+ func=func_path,
204
+ name=job_name,
205
+ kind=mlrun.runtimes.KubejobRuntime.kind,
206
+ handler=handler,
207
+ tag=tag,
208
+ image=image,
209
+ with_repo=with_repo,
210
+ requirements=requirements,
211
+ requirements_file=requirements_file,
212
+ ),
213
+ )
214
+
215
+ params: dict[str, Union[list[str], datetime]] = {}
216
+ if endpoint_names:
217
+ start, end = cls._validate_times(start, end)
218
+ params["endpoint_names"] = endpoint_names
219
+ params["start"] = start
220
+ params["end"] = end
221
+
222
+ inputs: dict[str, str] = {}
223
+ for data, identifier in [
224
+ (sample_data, "sample_data"),
225
+ (reference_data, "reference_data"),
226
+ ]:
227
+ if data is not None:
228
+ key = f"{job_name}_{identifier}"
229
+ inputs[identifier] = project.log_dataset(
230
+ key,
231
+ data,
232
+ labels={
233
+ mlrun_constants.MLRunInternalLabels.runner_pod: socket.gethostname(),
234
+ mlrun_constants.MLRunInternalLabels.producer_type: "model-monitoring-job",
235
+ mlrun_constants.MLRunInternalLabels.app_name: class_name,
236
+ },
237
+ ).uri
238
+
239
+ run_result = job.run(local=run_local, params=params, inputs=inputs)
240
+ return run_result
241
+
83
242
  @abstractmethod
84
243
  def do_tracking(
85
244
  self,
@@ -12,26 +12,36 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- import json
16
15
  import socket
17
- from typing import Any, Optional, cast
16
+ from typing import Any, Optional, Protocol, cast
18
17
 
18
+ import nuclio.request
19
19
  import numpy as np
20
20
  import pandas as pd
21
21
 
22
22
  import mlrun.common.constants as mlrun_constants
23
23
  import mlrun.common.schemas.model_monitoring.constants as mm_constants
24
+ import mlrun.errors
24
25
  import mlrun.feature_store as fstore
25
26
  import mlrun.features
26
27
  import mlrun.serving
27
28
  import mlrun.utils
28
29
  from mlrun.artifacts import Artifact, DatasetArtifact, ModelArtifact, get_model
29
- from mlrun.common.model_monitoring.helpers import FeatureStats, pad_features_hist
30
+ from mlrun.common.model_monitoring.helpers import FeatureStats
31
+ from mlrun.common.schemas import ModelEndpoint
30
32
  from mlrun.model_monitoring.helpers import (
31
33
  calculate_inputs_statistics,
32
- get_endpoint_record,
33
34
  )
34
- from mlrun.model_monitoring.model_endpoint import ModelEndpoint
35
+
36
+
37
+ class _ArtifactsLogger(Protocol):
38
+ """
39
+ Classes that implement this protocol are :code:`MlrunProject` and :code:`MLClientCtx`.
40
+ """
41
+
42
+ def log_artifact(self, *args, **kwargs) -> Artifact: ...
43
+ def log_dataset(self, *args, **kwargs) -> DatasetArtifact: ...
44
+ def log_model(self, *args, **kwargs) -> ModelArtifact: ...
35
45
 
36
46
 
37
47
  class MonitoringApplicationContext:
@@ -52,6 +62,7 @@ class MonitoringApplicationContext:
52
62
  :param end_infer_time: (pd.Timestamp) End time of the monitoring schedule.
53
63
  :param latest_request: (pd.Timestamp) Timestamp of the latest request on this endpoint_id.
54
64
  :param endpoint_id: (str) ID of the monitored model endpoint
65
+ :param endpoint_name: (str) Name of the monitored model endpoint
55
66
  :param output_stream_uri: (str) URI of the output stream for results
56
67
  :param model_endpoint: (ModelEndpoint) The model endpoint object.
57
68
  :param feature_names: (list[str]) List of models feature names.
@@ -60,36 +71,71 @@ class MonitoringApplicationContext:
60
71
  and a list of extra data items.
61
72
  """
62
73
 
74
+ _logger_name = "monitoring-application"
75
+
63
76
  def __init__(
64
77
  self,
65
78
  *,
66
- graph_context: mlrun.serving.GraphContext,
67
79
  application_name: str,
68
80
  event: dict[str, Any],
69
- model_endpoint_dict: dict[str, ModelEndpoint],
81
+ model_endpoint_dict: Optional[dict[str, ModelEndpoint]] = None,
82
+ logger: Optional[mlrun.utils.Logger] = None,
83
+ graph_context: Optional[mlrun.serving.GraphContext] = None,
84
+ context: Optional["mlrun.MLClientCtx"] = None,
85
+ artifacts_logger: Optional[_ArtifactsLogger] = None,
86
+ sample_df: Optional[pd.DataFrame] = None,
87
+ feature_stats: Optional[FeatureStats] = None,
70
88
  ) -> None:
71
89
  """
72
- Initialize a `MonitoringApplicationContext` object.
90
+ The :code:`__init__` method initializes a :code:`MonitoringApplicationContext` object
91
+ and has the following attributes.
73
92
  Note: this object should not be instantiated manually.
74
93
 
75
94
  :param application_name: The application name.
76
95
  :param event: The instance data dictionary.
77
- :param model_endpoint_dict: Dictionary of model endpoints.
96
+ :param model_endpoint_dict: Optional - dictionary of model endpoints.
97
+ :param logger: Optional - MLRun logger instance.
98
+ :param graph_context: Optional - GraphContext instance.
99
+ :param context: Optional - MLClientCtx instance.
100
+ :param artifacts_logger: Optional - an object that can log artifacts,
101
+ typically :py:class:`~mlrun.projects.MlrunProject` or
102
+ :py:class:`~mlrun.execution.MLClientCtx`.
103
+ :param sample_df: Optional - pandas data-frame as the current dataset.
104
+ When set, it replaces the data read from the offline source.
105
+ :param feature_stats: Optional - statistics dictionary of the reference data.
106
+ When set, it overrides the model endpoint's feature stats.
78
107
  """
79
108
  self.application_name = application_name
80
109
 
81
- self.project_name = graph_context.project
82
- self.project = mlrun.load_project(url=self.project_name)
110
+ if graph_context:
111
+ self.project_name = graph_context.project
112
+ self.project = mlrun.load_project(url=self.project_name)
113
+ elif context:
114
+ potential_project = context.get_project_object()
115
+ if not potential_project:
116
+ raise mlrun.errors.MLRunValueError(
117
+ "Could not load project from context"
118
+ )
119
+ self.project = potential_project
120
+ self.project_name = self.project.name
121
+
122
+ self._artifacts_logger: _ArtifactsLogger = artifacts_logger or self.project
83
123
 
84
124
  # MLRun Logger
85
- self.logger = mlrun.utils.create_logger(
125
+ self.logger = logger or mlrun.utils.create_logger(
86
126
  level=mlrun.mlconf.log_level,
87
127
  formatter_kind=mlrun.mlconf.log_formatter,
88
- name="monitoring-application",
128
+ name=self._logger_name,
89
129
  )
90
130
  # Nuclio logger - `nuclio.request.Logger`.
91
- # Note: this logger does not accept keyword arguments.
92
- self.nuclio_logger = graph_context.logger
131
+ # Note: this logger accepts keyword arguments only in its `_with` methods, e.g. `info_with`.
132
+ self.nuclio_logger = (
133
+ graph_context.logger
134
+ if graph_context
135
+ else nuclio.request.Logger(
136
+ level=mlrun.mlconf.log_level, name=self._logger_name
137
+ )
138
+ )
93
139
 
94
140
  # event data
95
141
  self.start_infer_time = pd.Timestamp(
@@ -101,29 +147,38 @@ class MonitoringApplicationContext:
101
147
  self.endpoint_id = cast(
102
148
  str, event.get(mm_constants.ApplicationEvent.ENDPOINT_ID)
103
149
  )
150
+ self.endpoint_name = cast(
151
+ str, event.get(mm_constants.ApplicationEvent.ENDPOINT_NAME)
152
+ )
104
153
  self.output_stream_uri = cast(
105
154
  str, event.get(mm_constants.ApplicationEvent.OUTPUT_STREAM_URI)
106
155
  )
107
156
 
108
- self._feature_stats: Optional[FeatureStats] = None
157
+ self._feature_stats: Optional[FeatureStats] = feature_stats
109
158
  self._sample_df_stats: Optional[FeatureStats] = None
110
159
 
111
160
  # Default labels for the artifacts
112
161
  self._default_labels = self._get_default_labels()
113
162
 
114
163
  # Persistent data - fetched when needed
115
- self._sample_df: Optional[pd.DataFrame] = None
116
- self._model_endpoint: Optional[ModelEndpoint] = model_endpoint_dict.get(
117
- self.endpoint_id
164
+ self._sample_df: Optional[pd.DataFrame] = sample_df
165
+ self._model_endpoint: Optional[ModelEndpoint] = (
166
+ model_endpoint_dict.get(self.endpoint_id) if model_endpoint_dict else None
118
167
  )
119
168
 
120
169
  def _get_default_labels(self) -> dict[str, str]:
121
- return {
170
+ labels = {
122
171
  mlrun_constants.MLRunInternalLabels.runner_pod: socket.gethostname(),
123
172
  mlrun_constants.MLRunInternalLabels.producer_type: "model-monitoring-app",
124
173
  mlrun_constants.MLRunInternalLabels.app_name: self.application_name,
125
- mlrun_constants.MLRunInternalLabels.endpoint_id: self.endpoint_id,
126
174
  }
175
+ for key, value in [
176
+ (mlrun_constants.MLRunInternalLabels.endpoint_id, self.endpoint_id),
177
+ (mlrun_constants.MLRunInternalLabels.endpoint_name, self.endpoint_name),
178
+ ]:
179
+ if value:
180
+ labels[key] = value
181
+ return labels
127
182
 
128
183
  def _add_default_labels(self, labels: Optional[dict[str, str]]) -> dict[str, str]:
129
184
  """Add the default labels to logged artifacts labels"""
@@ -133,7 +188,7 @@ class MonitoringApplicationContext:
133
188
  def sample_df(self) -> pd.DataFrame:
134
189
  if self._sample_df is None:
135
190
  feature_set = fstore.get_feature_set(
136
- self.model_endpoint.status.monitoring_feature_set_uri
191
+ self.model_endpoint.spec.monitoring_feature_set_uri
137
192
  )
138
193
  features = [f"{feature_set.metadata.name}.*"]
139
194
  vector = fstore.FeatureVector(
@@ -155,16 +210,18 @@ class MonitoringApplicationContext:
155
210
  @property
156
211
  def model_endpoint(self) -> ModelEndpoint:
157
212
  if not self._model_endpoint:
158
- self._model_endpoint = ModelEndpoint.from_flat_dict(
159
- get_endpoint_record(self.project_name, self.endpoint_id)
213
+ self._model_endpoint = mlrun.db.get_run_db().get_model_endpoint(
214
+ name=self.endpoint_name,
215
+ project=self.project_name,
216
+ endpoint_id=self.endpoint_id,
217
+ feature_analysis=True,
160
218
  )
161
219
  return self._model_endpoint
162
220
 
163
221
  @property
164
222
  def feature_stats(self) -> FeatureStats:
165
223
  if not self._feature_stats:
166
- self._feature_stats = json.loads(self.model_endpoint.status.feature_stats)
167
- pad_features_hist(self._feature_stats)
224
+ self._feature_stats = self.model_endpoint.spec.feature_stats
168
225
  return self._feature_stats
169
226
 
170
227
  @property
@@ -179,18 +236,12 @@ class MonitoringApplicationContext:
179
236
  @property
180
237
  def feature_names(self) -> list[str]:
181
238
  """The feature names of the model"""
182
- feature_names = self.model_endpoint.spec.feature_names
183
- return (
184
- feature_names
185
- if isinstance(feature_names, list)
186
- else json.loads(feature_names)
187
- )
239
+ return self.model_endpoint.spec.feature_names
188
240
 
189
241
  @property
190
242
  def label_names(self) -> list[str]:
191
243
  """The label names of the model"""
192
- label_names = self.model_endpoint.spec.label_names
193
- return label_names if isinstance(label_names, list) else json.loads(label_names)
244
+ return self.model_endpoint.spec.label_names
194
245
 
195
246
  @property
196
247
  def model(self) -> tuple[str, ModelArtifact, dict]:
@@ -237,7 +288,7 @@ class MonitoringApplicationContext:
237
288
  See :func:`~mlrun.projects.MlrunProject.log_artifact` for the documentation.
238
289
  """
239
290
  labels = self._add_default_labels(labels)
240
- return self.project.log_artifact(
291
+ return self._artifacts_logger.log_artifact(
241
292
  item,
242
293
  body=body,
243
294
  tag=tag,
@@ -272,7 +323,7 @@ class MonitoringApplicationContext:
272
323
  See :func:`~mlrun.projects.MlrunProject.log_dataset` for the documentation.
273
324
  """
274
325
  labels = self._add_default_labels(labels)
275
- return self.project.log_dataset(
326
+ return self._artifacts_logger.log_dataset(
276
327
  key,
277
328
  df,
278
329
  tag=tag,
@@ -317,7 +368,7 @@ class MonitoringApplicationContext:
317
368
  See :func:`~mlrun.projects.MlrunProject.log_model` for the documentation.
318
369
  """
319
370
  labels = self._add_default_labels(labels)
320
- return self.project.log_model(
371
+ return self._artifacts_logger.log_model(
321
372
  key,
322
373
  body=body,
323
374
  framework=framework,
@@ -76,7 +76,6 @@ class EvidentlyModelMonitoringApplicationBase(
76
76
 
77
77
  :param evidently_workspace_path: (str) The path to the Evidently workspace.
78
78
  :param evidently_project_id: (str) The ID of the Evidently project.
79
-
80
79
  """
81
80
 
82
81
  # TODO : more then one project (mep -> project)
@@ -113,7 +113,7 @@ class HistogramDataDriftApplication(ModelMonitoringApplicationBase):
113
113
 
114
114
  project.enable_model_monitoring()
115
115
 
116
- To avoid it, pass `deploy_histogram_data_drift_app=False`.
116
+ To avoid it, pass :code:`deploy_histogram_data_drift_app=False`.
117
117
  """
118
118
 
119
119
  NAME: Final[str] = HistogramDataDriftApplicationConstants.NAME
@@ -227,7 +227,7 @@ class HistogramDataDriftApplication(ModelMonitoringApplicationBase):
227
227
  :param metrics: the calculated metrics
228
228
  :param metrics_per_feature: metric calculated per feature
229
229
  :param monitoring_context: context object for current monitoring application
230
- :return: list of mm_results._ModelMonitoringApplicationStats for histogram data drift application
230
+ :returns: list of mm_results._ModelMonitoringApplicationStats for histogram data drift application
231
231
  """
232
232
  stats = []
233
233
  for stats_type in HistogramDataDriftApplication._STATS_TYPES:
@@ -331,8 +331,7 @@ class HistogramDataDriftApplication(ModelMonitoringApplicationBase):
331
331
  )
332
332
 
333
333
  def do_tracking(
334
- self,
335
- monitoring_context: mm_context.MonitoringApplicationContext,
334
+ self, monitoring_context: mm_context.MonitoringApplicationContext
336
335
  ) -> list[
337
336
  Union[
338
337
  mm_results.ModelMonitoringApplicationResult,
@@ -342,9 +341,6 @@ class HistogramDataDriftApplication(ModelMonitoringApplicationBase):
342
341
  ]:
343
342
  """
344
343
  Calculate and return the data drift metrics, averaged over the features.
345
-
346
- Refer to `ModelMonitoringApplicationBaseV2` for the meaning of the
347
- function arguments.
348
344
  """
349
345
  monitoring_context.logger.debug("Starting to run the application")
350
346
  if not monitoring_context.feature_stats: