mlrun 1.7.2rc3__py3-none-any.whl → 1.8.0__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 (275) hide show
  1. mlrun/__init__.py +26 -22
  2. mlrun/__main__.py +15 -16
  3. mlrun/alerts/alert.py +150 -15
  4. mlrun/api/schemas/__init__.py +1 -9
  5. mlrun/artifacts/__init__.py +2 -3
  6. mlrun/artifacts/base.py +62 -19
  7. mlrun/artifacts/dataset.py +17 -17
  8. mlrun/artifacts/document.py +454 -0
  9. mlrun/artifacts/manager.py +28 -18
  10. mlrun/artifacts/model.py +91 -59
  11. mlrun/artifacts/plots.py +2 -2
  12. mlrun/common/constants.py +8 -0
  13. mlrun/common/formatters/__init__.py +1 -0
  14. mlrun/common/formatters/artifact.py +1 -1
  15. mlrun/common/formatters/feature_set.py +2 -0
  16. mlrun/common/formatters/function.py +1 -0
  17. mlrun/{model_monitoring/db/stores/v3io_kv/__init__.py → common/formatters/model_endpoint.py} +17 -0
  18. mlrun/common/formatters/pipeline.py +1 -2
  19. mlrun/common/formatters/project.py +9 -0
  20. mlrun/common/model_monitoring/__init__.py +0 -5
  21. mlrun/common/model_monitoring/helpers.py +12 -62
  22. mlrun/common/runtimes/constants.py +25 -4
  23. mlrun/common/schemas/__init__.py +9 -5
  24. mlrun/common/schemas/alert.py +114 -19
  25. mlrun/common/schemas/api_gateway.py +3 -3
  26. mlrun/common/schemas/artifact.py +22 -9
  27. mlrun/common/schemas/auth.py +8 -4
  28. mlrun/common/schemas/background_task.py +7 -7
  29. mlrun/common/schemas/client_spec.py +4 -4
  30. mlrun/common/schemas/clusterization_spec.py +2 -2
  31. mlrun/common/schemas/common.py +53 -3
  32. mlrun/common/schemas/constants.py +15 -0
  33. mlrun/common/schemas/datastore_profile.py +1 -1
  34. mlrun/common/schemas/feature_store.py +9 -9
  35. mlrun/common/schemas/frontend_spec.py +4 -4
  36. mlrun/common/schemas/function.py +10 -10
  37. mlrun/common/schemas/hub.py +1 -1
  38. mlrun/common/schemas/k8s.py +3 -3
  39. mlrun/common/schemas/memory_reports.py +3 -3
  40. mlrun/common/schemas/model_monitoring/__init__.py +4 -8
  41. mlrun/common/schemas/model_monitoring/constants.py +127 -46
  42. mlrun/common/schemas/model_monitoring/grafana.py +18 -12
  43. mlrun/common/schemas/model_monitoring/model_endpoints.py +154 -160
  44. mlrun/common/schemas/notification.py +24 -3
  45. mlrun/common/schemas/object.py +1 -1
  46. mlrun/common/schemas/pagination.py +4 -4
  47. mlrun/common/schemas/partition.py +142 -0
  48. mlrun/common/schemas/pipeline.py +3 -3
  49. mlrun/common/schemas/project.py +26 -18
  50. mlrun/common/schemas/runs.py +3 -3
  51. mlrun/common/schemas/runtime_resource.py +5 -5
  52. mlrun/common/schemas/schedule.py +1 -1
  53. mlrun/common/schemas/secret.py +1 -1
  54. mlrun/{model_monitoring/db/stores/sqldb/__init__.py → common/schemas/serving.py} +10 -1
  55. mlrun/common/schemas/tag.py +3 -3
  56. mlrun/common/schemas/workflow.py +6 -5
  57. mlrun/common/types.py +1 -0
  58. mlrun/config.py +157 -89
  59. mlrun/data_types/__init__.py +5 -3
  60. mlrun/data_types/infer.py +13 -3
  61. mlrun/data_types/spark.py +2 -1
  62. mlrun/datastore/__init__.py +59 -18
  63. mlrun/datastore/alibaba_oss.py +4 -1
  64. mlrun/datastore/azure_blob.py +4 -1
  65. mlrun/datastore/base.py +19 -24
  66. mlrun/datastore/datastore.py +10 -4
  67. mlrun/datastore/datastore_profile.py +178 -45
  68. mlrun/datastore/dbfs_store.py +4 -1
  69. mlrun/datastore/filestore.py +4 -1
  70. mlrun/datastore/google_cloud_storage.py +4 -1
  71. mlrun/datastore/hdfs.py +4 -1
  72. mlrun/datastore/inmem.py +4 -1
  73. mlrun/datastore/redis.py +4 -1
  74. mlrun/datastore/s3.py +14 -3
  75. mlrun/datastore/sources.py +89 -92
  76. mlrun/datastore/store_resources.py +7 -4
  77. mlrun/datastore/storeytargets.py +51 -16
  78. mlrun/datastore/targets.py +38 -31
  79. mlrun/datastore/utils.py +87 -4
  80. mlrun/datastore/v3io.py +4 -1
  81. mlrun/datastore/vectorstore.py +291 -0
  82. mlrun/datastore/wasbfs/fs.py +13 -12
  83. mlrun/db/base.py +286 -100
  84. mlrun/db/httpdb.py +1562 -490
  85. mlrun/db/nopdb.py +250 -83
  86. mlrun/errors.py +6 -2
  87. mlrun/execution.py +194 -50
  88. mlrun/feature_store/__init__.py +2 -10
  89. mlrun/feature_store/api.py +20 -458
  90. mlrun/feature_store/common.py +9 -9
  91. mlrun/feature_store/feature_set.py +20 -18
  92. mlrun/feature_store/feature_vector.py +105 -479
  93. mlrun/feature_store/feature_vector_utils.py +466 -0
  94. mlrun/feature_store/retrieval/base.py +15 -11
  95. mlrun/feature_store/retrieval/job.py +2 -1
  96. mlrun/feature_store/retrieval/storey_merger.py +1 -1
  97. mlrun/feature_store/steps.py +3 -3
  98. mlrun/features.py +30 -13
  99. mlrun/frameworks/__init__.py +1 -2
  100. mlrun/frameworks/_common/__init__.py +1 -2
  101. mlrun/frameworks/_common/artifacts_library.py +2 -2
  102. mlrun/frameworks/_common/mlrun_interface.py +10 -6
  103. mlrun/frameworks/_common/model_handler.py +31 -31
  104. mlrun/frameworks/_common/producer.py +3 -1
  105. mlrun/frameworks/_dl_common/__init__.py +1 -2
  106. mlrun/frameworks/_dl_common/loggers/__init__.py +1 -2
  107. mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +4 -4
  108. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +3 -3
  109. mlrun/frameworks/_ml_common/__init__.py +1 -2
  110. mlrun/frameworks/_ml_common/loggers/__init__.py +1 -2
  111. mlrun/frameworks/_ml_common/model_handler.py +21 -21
  112. mlrun/frameworks/_ml_common/plans/__init__.py +1 -2
  113. mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +3 -1
  114. mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
  115. mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
  116. mlrun/frameworks/auto_mlrun/__init__.py +1 -2
  117. mlrun/frameworks/auto_mlrun/auto_mlrun.py +22 -15
  118. mlrun/frameworks/huggingface/__init__.py +1 -2
  119. mlrun/frameworks/huggingface/model_server.py +9 -9
  120. mlrun/frameworks/lgbm/__init__.py +47 -44
  121. mlrun/frameworks/lgbm/callbacks/__init__.py +1 -2
  122. mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -2
  123. mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -2
  124. mlrun/frameworks/lgbm/mlrun_interfaces/__init__.py +1 -2
  125. mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +5 -5
  126. mlrun/frameworks/lgbm/model_handler.py +15 -11
  127. mlrun/frameworks/lgbm/model_server.py +11 -7
  128. mlrun/frameworks/lgbm/utils.py +2 -2
  129. mlrun/frameworks/onnx/__init__.py +1 -2
  130. mlrun/frameworks/onnx/dataset.py +3 -3
  131. mlrun/frameworks/onnx/mlrun_interface.py +2 -2
  132. mlrun/frameworks/onnx/model_handler.py +7 -5
  133. mlrun/frameworks/onnx/model_server.py +8 -6
  134. mlrun/frameworks/parallel_coordinates.py +11 -11
  135. mlrun/frameworks/pytorch/__init__.py +22 -23
  136. mlrun/frameworks/pytorch/callbacks/__init__.py +1 -2
  137. mlrun/frameworks/pytorch/callbacks/callback.py +2 -1
  138. mlrun/frameworks/pytorch/callbacks/logging_callback.py +15 -8
  139. mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +19 -12
  140. mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +22 -15
  141. mlrun/frameworks/pytorch/callbacks_handler.py +36 -30
  142. mlrun/frameworks/pytorch/mlrun_interface.py +17 -17
  143. mlrun/frameworks/pytorch/model_handler.py +21 -17
  144. mlrun/frameworks/pytorch/model_server.py +13 -9
  145. mlrun/frameworks/sklearn/__init__.py +19 -18
  146. mlrun/frameworks/sklearn/estimator.py +2 -2
  147. mlrun/frameworks/sklearn/metric.py +3 -3
  148. mlrun/frameworks/sklearn/metrics_library.py +8 -6
  149. mlrun/frameworks/sklearn/mlrun_interface.py +3 -2
  150. mlrun/frameworks/sklearn/model_handler.py +4 -3
  151. mlrun/frameworks/tf_keras/__init__.py +11 -12
  152. mlrun/frameworks/tf_keras/callbacks/__init__.py +1 -2
  153. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +17 -14
  154. mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +15 -12
  155. mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +21 -18
  156. mlrun/frameworks/tf_keras/model_handler.py +17 -13
  157. mlrun/frameworks/tf_keras/model_server.py +12 -8
  158. mlrun/frameworks/xgboost/__init__.py +19 -18
  159. mlrun/frameworks/xgboost/model_handler.py +13 -9
  160. mlrun/k8s_utils.py +2 -5
  161. mlrun/launcher/base.py +3 -4
  162. mlrun/launcher/client.py +2 -2
  163. mlrun/launcher/local.py +6 -2
  164. mlrun/launcher/remote.py +1 -1
  165. mlrun/lists.py +8 -4
  166. mlrun/model.py +132 -46
  167. mlrun/model_monitoring/__init__.py +3 -5
  168. mlrun/model_monitoring/api.py +113 -98
  169. mlrun/model_monitoring/applications/__init__.py +0 -5
  170. mlrun/model_monitoring/applications/_application_steps.py +81 -50
  171. mlrun/model_monitoring/applications/base.py +467 -14
  172. mlrun/model_monitoring/applications/context.py +212 -134
  173. mlrun/model_monitoring/{db/stores/base → applications/evidently}/__init__.py +6 -2
  174. mlrun/model_monitoring/applications/evidently/base.py +146 -0
  175. mlrun/model_monitoring/applications/histogram_data_drift.py +89 -56
  176. mlrun/model_monitoring/applications/results.py +67 -15
  177. mlrun/model_monitoring/controller.py +701 -315
  178. mlrun/model_monitoring/db/__init__.py +0 -2
  179. mlrun/model_monitoring/db/_schedules.py +242 -0
  180. mlrun/model_monitoring/db/_stats.py +189 -0
  181. mlrun/model_monitoring/db/tsdb/__init__.py +33 -22
  182. mlrun/model_monitoring/db/tsdb/base.py +243 -49
  183. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +76 -36
  184. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +33 -0
  185. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connection.py +213 -0
  186. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +534 -88
  187. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +1 -0
  188. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +436 -106
  189. mlrun/model_monitoring/helpers.py +356 -114
  190. mlrun/model_monitoring/stream_processing.py +190 -345
  191. mlrun/model_monitoring/tracking_policy.py +11 -4
  192. mlrun/model_monitoring/writer.py +49 -90
  193. mlrun/package/__init__.py +3 -6
  194. mlrun/package/context_handler.py +2 -2
  195. mlrun/package/packager.py +12 -9
  196. mlrun/package/packagers/__init__.py +0 -2
  197. mlrun/package/packagers/default_packager.py +14 -11
  198. mlrun/package/packagers/numpy_packagers.py +16 -7
  199. mlrun/package/packagers/pandas_packagers.py +18 -18
  200. mlrun/package/packagers/python_standard_library_packagers.py +25 -11
  201. mlrun/package/packagers_manager.py +35 -32
  202. mlrun/package/utils/__init__.py +0 -3
  203. mlrun/package/utils/_pickler.py +6 -6
  204. mlrun/platforms/__init__.py +47 -16
  205. mlrun/platforms/iguazio.py +4 -1
  206. mlrun/projects/operations.py +30 -30
  207. mlrun/projects/pipelines.py +116 -47
  208. mlrun/projects/project.py +1292 -329
  209. mlrun/render.py +5 -9
  210. mlrun/run.py +57 -14
  211. mlrun/runtimes/__init__.py +1 -3
  212. mlrun/runtimes/base.py +30 -22
  213. mlrun/runtimes/daskjob.py +9 -9
  214. mlrun/runtimes/databricks_job/databricks_runtime.py +6 -5
  215. mlrun/runtimes/function_reference.py +5 -2
  216. mlrun/runtimes/generators.py +3 -2
  217. mlrun/runtimes/kubejob.py +6 -7
  218. mlrun/runtimes/mounts.py +574 -0
  219. mlrun/runtimes/mpijob/__init__.py +0 -2
  220. mlrun/runtimes/mpijob/abstract.py +7 -6
  221. mlrun/runtimes/nuclio/api_gateway.py +7 -7
  222. mlrun/runtimes/nuclio/application/application.py +11 -13
  223. mlrun/runtimes/nuclio/application/reverse_proxy.go +66 -64
  224. mlrun/runtimes/nuclio/function.py +127 -70
  225. mlrun/runtimes/nuclio/serving.py +105 -37
  226. mlrun/runtimes/pod.py +159 -54
  227. mlrun/runtimes/remotesparkjob.py +3 -2
  228. mlrun/runtimes/sparkjob/__init__.py +0 -2
  229. mlrun/runtimes/sparkjob/spark3job.py +22 -12
  230. mlrun/runtimes/utils.py +7 -6
  231. mlrun/secrets.py +2 -2
  232. mlrun/serving/__init__.py +8 -0
  233. mlrun/serving/merger.py +7 -5
  234. mlrun/serving/remote.py +35 -22
  235. mlrun/serving/routers.py +186 -240
  236. mlrun/serving/server.py +41 -10
  237. mlrun/serving/states.py +432 -118
  238. mlrun/serving/utils.py +13 -2
  239. mlrun/serving/v1_serving.py +3 -2
  240. mlrun/serving/v2_serving.py +161 -203
  241. mlrun/track/__init__.py +1 -1
  242. mlrun/track/tracker.py +2 -2
  243. mlrun/track/trackers/mlflow_tracker.py +6 -5
  244. mlrun/utils/async_http.py +35 -22
  245. mlrun/utils/clones.py +7 -4
  246. mlrun/utils/helpers.py +511 -58
  247. mlrun/utils/logger.py +119 -13
  248. mlrun/utils/notifications/notification/__init__.py +22 -19
  249. mlrun/utils/notifications/notification/base.py +39 -15
  250. mlrun/utils/notifications/notification/console.py +6 -6
  251. mlrun/utils/notifications/notification/git.py +11 -11
  252. mlrun/utils/notifications/notification/ipython.py +10 -9
  253. mlrun/utils/notifications/notification/mail.py +176 -0
  254. mlrun/utils/notifications/notification/slack.py +16 -8
  255. mlrun/utils/notifications/notification/webhook.py +24 -8
  256. mlrun/utils/notifications/notification_pusher.py +191 -200
  257. mlrun/utils/regex.py +12 -2
  258. mlrun/utils/version/version.json +2 -2
  259. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info}/METADATA +81 -54
  260. mlrun-1.8.0.dist-info/RECORD +351 -0
  261. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info}/WHEEL +1 -1
  262. mlrun/model_monitoring/applications/evidently_base.py +0 -137
  263. mlrun/model_monitoring/db/stores/__init__.py +0 -136
  264. mlrun/model_monitoring/db/stores/base/store.py +0 -213
  265. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -71
  266. mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -190
  267. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +0 -103
  268. mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -40
  269. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +0 -659
  270. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +0 -726
  271. mlrun/model_monitoring/model_endpoint.py +0 -118
  272. mlrun-1.7.2rc3.dist-info/RECORD +0 -351
  273. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info}/entry_points.txt +0 -0
  274. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info/licenses}/LICENSE +0 -0
  275. {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info}/top_level.txt +0 -0
@@ -13,7 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import warnings
16
- from typing import Union
16
+ from typing import Optional, Union
17
17
 
18
18
  import mlrun.common.schemas.schedule
19
19
  import mlrun.model
@@ -57,7 +57,7 @@ class TrackingPolicy(mlrun.model.ModelObj):
57
57
  """
58
58
  warnings.warn(
59
59
  "The `TrackingPolicy` class is deprecated from version 1.7.0 and is not "
60
- "used anymore. It will be removed in 1.9.0.",
60
+ "used anymore. It will be removed in 1.10.0.",
61
61
  FutureWarning,
62
62
  )
63
63
 
@@ -74,7 +74,9 @@ class TrackingPolicy(mlrun.model.ModelObj):
74
74
  self.default_controller_image = default_controller_image
75
75
 
76
76
  @classmethod
77
- def from_dict(cls, struct=None, fields=None, deprecated_fields: dict = None):
77
+ def from_dict(
78
+ cls, struct=None, fields=None, deprecated_fields: Optional[dict] = None
79
+ ):
78
80
  new_obj = super().from_dict(
79
81
  struct, fields=cls._dict_fields, deprecated_fields=deprecated_fields
80
82
  )
@@ -102,7 +104,12 @@ class TrackingPolicy(mlrun.model.ModelObj):
102
104
  )
103
105
  return new_obj
104
106
 
105
- def to_dict(self, fields: list = None, exclude: list = None, strip: bool = False):
107
+ def to_dict(
108
+ self,
109
+ fields: Optional[list] = None,
110
+ exclude: Optional[list] = None,
111
+ strip: bool = False,
112
+ ):
106
113
  struct = super().to_dict(
107
114
  fields,
108
115
  exclude=[
@@ -13,27 +13,31 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import json
16
- from typing import Any, Callable, NewType
16
+ from datetime import datetime, timezone
17
+ from typing import Any, Callable, NewType, Optional
17
18
 
18
19
  import mlrun.common.model_monitoring
19
20
  import mlrun.common.schemas
20
21
  import mlrun.common.schemas.alert as alert_objects
21
22
  import mlrun.model_monitoring
22
23
  from mlrun.common.schemas.model_monitoring.constants import (
23
- EventFieldType,
24
24
  HistogramDataDriftApplicationConstants,
25
25
  MetricData,
26
26
  ResultData,
27
27
  ResultKindApp,
28
28
  ResultStatusApp,
29
+ StatsData,
30
+ StatsKind,
29
31
  WriterEvent,
30
32
  WriterEventKind,
31
33
  )
32
- from mlrun.common.schemas.notification import NotificationKind, NotificationSeverity
34
+ from mlrun.model_monitoring.db._stats import (
35
+ ModelMonitoringCurrentStatsFile,
36
+ ModelMonitoringDriftMeasuresFile,
37
+ )
33
38
  from mlrun.model_monitoring.helpers import get_result_instance_fqn
34
39
  from mlrun.serving.utils import StepToDict
35
40
  from mlrun.utils import logger
36
- from mlrun.utils.notifications.notification_pusher import CustomNotificationPusher
37
41
 
38
42
  _RawEvent = dict[str, Any]
39
43
  _AppResultEvent = NewType("_AppResultEvent", _RawEvent)
@@ -51,50 +55,6 @@ class _WriterEventTypeError(_WriterEventError, TypeError):
51
55
  pass
52
56
 
53
57
 
54
- class _Notifier:
55
- def __init__(
56
- self,
57
- event: _AppResultEvent,
58
- notification_pusher: CustomNotificationPusher,
59
- severity: NotificationSeverity = NotificationSeverity.WARNING,
60
- ) -> None:
61
- """
62
- Event notifier - send push notification when appropriate to the notifiers in
63
- `notification pusher`.
64
- Note that if you use a Slack App webhook, you need to define it as an MLRun secret
65
- `SLACK_WEBHOOK`.
66
- """
67
- self._event = event
68
- self._custom_notifier = notification_pusher
69
- self._severity = severity
70
-
71
- def _should_send_event(self) -> bool:
72
- return self._event[ResultData.RESULT_STATUS] >= ResultStatusApp.detected.value
73
-
74
- def _generate_message(self) -> str:
75
- return f"""\
76
- The monitoring app `{self._event[WriterEvent.APPLICATION_NAME]}` \
77
- of kind `{self._event[ResultData.RESULT_KIND]}` \
78
- detected a problem in model endpoint ID `{self._event[WriterEvent.ENDPOINT_ID]}` \
79
- at time `{self._event[WriterEvent.START_INFER_TIME]}`.
80
-
81
- Result data:
82
- Name: `{self._event[ResultData.RESULT_NAME]}`
83
- Value: `{self._event[ResultData.RESULT_VALUE]}`
84
- Status: `{self._event[ResultData.RESULT_STATUS]}`
85
- Extra data: `{self._event[ResultData.RESULT_EXTRA_DATA]}`\
86
- """
87
-
88
- def notify(self) -> None:
89
- """Send notification if appropriate"""
90
- if not self._should_send_event():
91
- logger.debug("Not sending a notification")
92
- return
93
- message = self._generate_message()
94
- self._custom_notifier.push(message=message, severity=self._severity)
95
- logger.debug("A notification should have been sent")
96
-
97
-
98
58
  class ModelMonitoringWriter(StepToDict):
99
59
  """
100
60
  Write monitoring application results to the target databases
@@ -105,18 +65,11 @@ class ModelMonitoringWriter(StepToDict):
105
65
  def __init__(
106
66
  self,
107
67
  project: str,
108
- secret_provider: Callable = None,
68
+ secret_provider: Optional[Callable] = None,
109
69
  ) -> None:
110
70
  self.project = project
111
71
  self.name = project # required for the deployment process
112
72
 
113
- self._custom_notifier = CustomNotificationPusher(
114
- notification_types=[NotificationKind.slack]
115
- )
116
-
117
- self._app_result_store = mlrun.model_monitoring.get_store_object(
118
- project=self.project, secret_provider=secret_provider
119
- )
120
73
  self._tsdb_connector = mlrun.model_monitoring.get_tsdb_connector(
121
74
  project=self.project, secret_provider=secret_provider
122
75
  )
@@ -176,7 +129,7 @@ class ModelMonitoringWriter(StepToDict):
176
129
  )
177
130
  kind = event.pop(WriterEvent.EVENT_KIND, WriterEventKind.RESULT)
178
131
  result_event = _AppResultEvent(json.loads(event.pop(WriterEvent.DATA, "{}")))
179
- if not result_event: # BC for < 1.7.0, can be removed in 1.9.0
132
+ if not result_event: # BC for < 1.7.0, can be removed in 1.10.0
180
133
  result_event = _AppResultEvent(event)
181
134
  else:
182
135
  result_event.update(_AppResultEvent(event))
@@ -190,6 +143,8 @@ class ModelMonitoringWriter(StepToDict):
190
143
  expected_keys.extend(MetricData.list())
191
144
  elif kind == WriterEventKind.RESULT:
192
145
  expected_keys.extend(ResultData.list())
146
+ elif kind == WriterEventKind.STATS:
147
+ expected_keys.extend(StatsData.list())
193
148
  else:
194
149
  raise _WriterEventValueError(
195
150
  f"Unknown event kind: {kind}, expected one of: {WriterEventKind.list()}"
@@ -198,22 +153,53 @@ class ModelMonitoringWriter(StepToDict):
198
153
  if missing_keys:
199
154
  raise _WriterEventValueError(
200
155
  f"The received event misses some keys compared to the expected "
201
- f"monitoring application event schema: {missing_keys}"
156
+ f"monitoring application event schema: {missing_keys} for event kind {kind}"
202
157
  )
203
158
 
204
159
  return result_event, kind
205
160
 
161
+ def write_stats(self, event: _AppResultEvent) -> None:
162
+ """
163
+ Write to file the application stats event
164
+ :param event: application stats event
165
+ """
166
+ endpoint_id = event[WriterEvent.ENDPOINT_ID]
167
+ logger.debug(
168
+ "Updating the model endpoint with stats",
169
+ endpoint_id=endpoint_id,
170
+ )
171
+ stat_kind = event.get(StatsData.STATS_NAME)
172
+ data, timestamp_str = event.get(StatsData.STATS), event.get(StatsData.TIMESTAMP)
173
+ timestamp = datetime.fromisoformat(timestamp_str).astimezone(tz=timezone.utc)
174
+ if stat_kind == StatsKind.CURRENT_STATS.value:
175
+ ModelMonitoringCurrentStatsFile(self.project, endpoint_id).write(
176
+ data, timestamp
177
+ )
178
+ elif stat_kind == StatsKind.DRIFT_MEASURES.value:
179
+ ModelMonitoringDriftMeasuresFile(self.project, endpoint_id).write(
180
+ data, timestamp
181
+ )
182
+ logger.info(
183
+ "Updated the model endpoint statistics",
184
+ endpoint_id=endpoint_id,
185
+ stats_kind=stat_kind,
186
+ )
187
+
206
188
  def do(self, event: _RawEvent) -> None:
207
189
  event, kind = self._reconstruct_event(event)
208
190
  logger.info("Starting to write event", event=event)
191
+ if (
192
+ kind == WriterEventKind.STATS
193
+ and event[WriterEvent.APPLICATION_NAME]
194
+ == HistogramDataDriftApplicationConstants.NAME
195
+ ):
196
+ self.write_stats(event)
197
+ logger.info("Model monitoring writer finished handling event")
198
+ return
209
199
  self._tsdb_connector.write_application_event(event=event.copy(), kind=kind)
210
- self._app_result_store.write_application_event(event=event.copy(), kind=kind)
211
200
 
212
201
  logger.info("Completed event DB writes")
213
202
 
214
- if kind == WriterEventKind.RESULT:
215
- _Notifier(event=event, notification_pusher=self._custom_notifier).notify()
216
-
217
203
  if (
218
204
  mlrun.mlconf.alerts.mode == mlrun.common.schemas.alert.AlertsModes.enabled
219
205
  and kind == WriterEventKind.RESULT
@@ -223,14 +209,9 @@ class ModelMonitoringWriter(StepToDict):
223
209
  == ResultStatusApp.potential_detection.value
224
210
  )
225
211
  ):
226
- endpoint_id = event[WriterEvent.ENDPOINT_ID]
227
- endpoint_record = self._endpoints_records.setdefault(
228
- endpoint_id,
229
- self._app_result_store.get_model_endpoint(endpoint_id=endpoint_id),
230
- )
231
212
  event_value = {
232
213
  "app_name": event[WriterEvent.APPLICATION_NAME],
233
- "model": endpoint_record.get(EventFieldType.MODEL),
214
+ "model": event[WriterEvent.ENDPOINT_NAME],
234
215
  "model_endpoint_id": event[WriterEvent.ENDPOINT_ID],
235
216
  "result_name": event[ResultData.RESULT_NAME],
236
217
  "result_value": event[ResultData.RESULT_VALUE],
@@ -247,26 +228,4 @@ class ModelMonitoringWriter(StepToDict):
247
228
  result_kind=event[ResultData.RESULT_KIND],
248
229
  )
249
230
 
250
- if (
251
- kind == WriterEventKind.RESULT
252
- and event[WriterEvent.APPLICATION_NAME]
253
- == HistogramDataDriftApplicationConstants.NAME
254
- and event[ResultData.RESULT_NAME]
255
- == HistogramDataDriftApplicationConstants.GENERAL_RESULT_NAME
256
- ):
257
- endpoint_id = event[WriterEvent.ENDPOINT_ID]
258
- logger.info(
259
- "Updating the model endpoint with metadata specific to the histogram "
260
- "data drift app",
261
- endpoint_id=endpoint_id,
262
- )
263
- attributes = json.loads(event[ResultData.RESULT_EXTRA_DATA])
264
- attributes[EventFieldType.DRIFT_STATUS] = str(
265
- attributes[EventFieldType.DRIFT_STATUS]
266
- )
267
- self._app_result_store.update_model_endpoint(
268
- endpoint_id=endpoint_id,
269
- attributes=attributes,
270
- )
271
-
272
231
  logger.info("Model monitoring writer finished handling event")
mlrun/package/__init__.py CHANGED
@@ -11,14 +11,11 @@
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
- #
15
-
16
- # flake8: noqa - this is until we take care of the F401 violations with respect to __all__ & sphinx
17
14
 
18
15
  import functools
19
16
  import inspect
20
17
  from collections import OrderedDict
21
- from typing import Callable, Union
18
+ from typing import Callable, Optional, Union
22
19
 
23
20
  from ..config import config
24
21
  from .context_handler import ContextHandler
@@ -40,8 +37,8 @@ from .utils import (
40
37
 
41
38
 
42
39
  def handler(
43
- labels: dict[str, str] = None,
44
- outputs: list[Union[str, dict[str, str]]] = None,
40
+ labels: Optional[dict[str, str]] = None,
41
+ outputs: Optional[list[Union[str, dict[str, str]]]] = None,
45
42
  inputs: Union[bool, dict[str, Union[str, type]]] = True,
46
43
  ):
47
44
  """
@@ -50,7 +50,7 @@ class ContextHandler:
50
50
  "numpy",
51
51
  ]
52
52
  # Optional packagers to be collected at initialization time:
53
- _EXTENDED_PACKAGERS = [] # TODO: Create "matplotlib", "plotly", "bokeh" packagers.
53
+ _EXTENDED_PACKAGERS = [] # TODO: Create "matplotlib", "plotly", packagers.
54
54
  # Optional packagers from the `mlrun.frameworks` package:
55
55
  _MLRUN_FRAMEWORKS_PACKAGERS = [] # TODO: Create frameworks packagers.
56
56
  # Default priority values for packagers:
@@ -216,7 +216,7 @@ class ContextHandler:
216
216
  )
217
217
  # Link packages:
218
218
  self._packagers_manager.link_packages(
219
- additional_artifacts=self._context.artifacts,
219
+ additional_artifact_uris=self._context.artifact_uris,
220
220
  additional_results=self._context.results,
221
221
  )
222
222
  # Log the packed results and artifacts:
mlrun/package/packager.py CHANGED
@@ -14,7 +14,7 @@
14
14
  #
15
15
  from abc import ABC, abstractmethod
16
16
  from pathlib import Path
17
- from typing import Any, Union
17
+ from typing import Any, Optional, Union
18
18
 
19
19
  from mlrun.artifacts import Artifact
20
20
  from mlrun.datastore import DataItem
@@ -144,9 +144,9 @@ class Packager(ABC):
144
144
  def pack(
145
145
  self,
146
146
  obj: Any,
147
- key: str = None,
148
- artifact_type: str = None,
149
- configurations: dict = None,
147
+ key: Optional[str] = None,
148
+ artifact_type: Optional[str] = None,
149
+ configurations: Optional[dict] = None,
150
150
  ) -> Union[tuple[Artifact, dict], dict]:
151
151
  """
152
152
  Pack an object as the given artifact type using the provided configurations.
@@ -165,8 +165,8 @@ class Packager(ABC):
165
165
  def unpack(
166
166
  self,
167
167
  data_item: DataItem,
168
- artifact_type: str = None,
169
- instructions: dict = None,
168
+ artifact_type: Optional[str] = None,
169
+ instructions: Optional[dict] = None,
170
170
  ) -> Any:
171
171
  """
172
172
  Unpack the data item's artifact by the provided type using the given instructions.
@@ -180,7 +180,10 @@ class Packager(ABC):
180
180
  pass
181
181
 
182
182
  def is_packable(
183
- self, obj: Any, artifact_type: str = None, configurations: dict = None
183
+ self,
184
+ obj: Any,
185
+ artifact_type: Optional[str] = None,
186
+ configurations: Optional[dict] = None,
184
187
  ) -> bool:
185
188
  """
186
189
  Check if this packager can pack an object of the provided type as the provided artifact type.
@@ -212,7 +215,7 @@ class Packager(ABC):
212
215
  return True
213
216
 
214
217
  def is_unpackable(
215
- self, data_item: DataItem, type_hint: type, artifact_type: str = None
218
+ self, data_item: DataItem, type_hint: type, artifact_type: Optional[str] = None
216
219
  ) -> bool:
217
220
  """
218
221
  Check if this packager can unpack an input according to the user-given type hint and the provided artifact type.
@@ -315,7 +318,7 @@ class Packager(ABC):
315
318
  )
316
319
 
317
320
  def get_data_item_local_path(
318
- self, data_item: DataItem, add_to_future_clearing_path: bool = None
321
+ self, data_item: DataItem, add_to_future_clearing_path: Optional[bool] = None
319
322
  ) -> str:
320
323
  """
321
324
  Get the local path to the item handled by the data item provided. The local path can be the same as the data
@@ -11,8 +11,6 @@
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
- #
15
14
 
16
- # flake8: noqa - this is until we take care of the F401 violations with respect to __all__ & sphinx
17
15
  from .default_packager import DefaultPackager
18
16
  from .numpy_packagers import NumPySupportedFormat
@@ -15,7 +15,7 @@
15
15
  import inspect
16
16
  from abc import ABCMeta
17
17
  from types import MethodType
18
- from typing import Any, Union
18
+ from typing import Any, Optional, Union
19
19
 
20
20
  import docstring_parser
21
21
 
@@ -323,9 +323,9 @@ class DefaultPackager(Packager, metaclass=_DefaultPackagerMeta):
323
323
  def pack(
324
324
  self,
325
325
  obj: Any,
326
- key: str = None,
327
- artifact_type: str = None,
328
- configurations: dict = None,
326
+ key: Optional[str] = None,
327
+ artifact_type: Optional[str] = None,
328
+ configurations: Optional[dict] = None,
329
329
  ) -> Union[tuple[Artifact, dict], dict]:
330
330
  """
331
331
  Pack an object as the given artifact type using the provided configurations.
@@ -361,8 +361,8 @@ class DefaultPackager(Packager, metaclass=_DefaultPackagerMeta):
361
361
  def unpack(
362
362
  self,
363
363
  data_item: DataItem,
364
- artifact_type: str = None,
365
- instructions: dict = None,
364
+ artifact_type: Optional[str] = None,
365
+ instructions: Optional[dict] = None,
366
366
  ) -> Any:
367
367
  """
368
368
  Unpack the data item's artifact by the provided type using the given instructions.
@@ -399,7 +399,10 @@ class DefaultPackager(Packager, metaclass=_DefaultPackagerMeta):
399
399
  return unpack_method(data_item, **instructions)
400
400
 
401
401
  def is_packable(
402
- self, obj: Any, artifact_type: str = None, configurations: dict = None
402
+ self,
403
+ obj: Any,
404
+ artifact_type: Optional[str] = None,
405
+ configurations: Optional[dict] = None,
403
406
  ) -> bool:
404
407
  """
405
408
  Check if this packager can pack an object of the provided type as the provided artifact type.
@@ -480,10 +483,10 @@ class DefaultPackager(Packager, metaclass=_DefaultPackagerMeta):
480
483
  self,
481
484
  data_item: DataItem,
482
485
  pickle_module_name: str = DEFAULT_PICKLE_MODULE,
483
- object_module_name: str = None,
484
- python_version: str = None,
485
- pickle_module_version: str = None,
486
- object_module_version: str = None,
486
+ object_module_name: Optional[str] = None,
487
+ python_version: Optional[str] = None,
488
+ pickle_module_version: Optional[str] = None,
489
+ object_module_version: Optional[str] = None,
487
490
  ) -> Any:
488
491
  """
489
492
  Unpack the data item's object, unpickle it using the instructions, and return.
@@ -16,7 +16,7 @@ import os
16
16
  import pathlib
17
17
  import tempfile
18
18
  from abc import ABC, abstractmethod
19
- from typing import Any, Union
19
+ from typing import Any, Optional, Union
20
20
 
21
21
  import numpy as np
22
22
  import pandas as pd
@@ -371,7 +371,10 @@ class NumPyNDArrayPackager(DefaultPackager):
371
371
  return artifact, {}
372
372
 
373
373
  def unpack_file(
374
- self, data_item: DataItem, file_format: str = None, allow_pickle: bool = False
374
+ self,
375
+ data_item: DataItem,
376
+ file_format: Optional[str] = None,
377
+ allow_pickle: bool = False,
375
378
  ) -> np.ndarray:
376
379
  """
377
380
  Unpack a numppy array from file.
@@ -474,7 +477,7 @@ class _NumPyNDArrayCollectionPackager(DefaultPackager):
474
477
  def unpack_file(
475
478
  self,
476
479
  data_item: DataItem,
477
- file_format: str = None,
480
+ file_format: Optional[str] = None,
478
481
  allow_pickle: bool = False,
479
482
  ) -> dict[str, np.ndarray]:
480
483
  """
@@ -548,7 +551,10 @@ class NumPyNDArrayDictPackager(_NumPyNDArrayCollectionPackager):
548
551
  PACKABLE_OBJECT_TYPE = dict[str, np.ndarray]
549
552
 
550
553
  def is_packable(
551
- self, obj: Any, artifact_type: str = None, configurations: dict = None
554
+ self,
555
+ obj: Any,
556
+ artifact_type: Optional[str] = None,
557
+ configurations: Optional[dict] = None,
552
558
  ) -> bool:
553
559
  """
554
560
  Check if the object provided is a dictionary of numpy arrays.
@@ -602,7 +608,7 @@ class NumPyNDArrayDictPackager(_NumPyNDArrayCollectionPackager):
602
608
  def unpack_file(
603
609
  self,
604
610
  data_item: DataItem,
605
- file_format: str = None,
611
+ file_format: Optional[str] = None,
606
612
  allow_pickle: bool = False,
607
613
  ) -> dict[str, np.ndarray]:
608
614
  """
@@ -633,7 +639,10 @@ class NumPyNDArrayListPackager(_NumPyNDArrayCollectionPackager):
633
639
  PACKABLE_OBJECT_TYPE = list[np.ndarray]
634
640
 
635
641
  def is_packable(
636
- self, obj: Any, artifact_type: str = None, configurations: dict = None
642
+ self,
643
+ obj: Any,
644
+ artifact_type: Optional[str] = None,
645
+ configurations: Optional[dict] = None,
637
646
  ) -> bool:
638
647
  """
639
648
  Check if the object provided is a list of numpy arrays.
@@ -679,7 +688,7 @@ class NumPyNDArrayListPackager(_NumPyNDArrayCollectionPackager):
679
688
  def unpack_file(
680
689
  self,
681
690
  data_item: DataItem,
682
- file_format: str = None,
691
+ file_format: Optional[str] = None,
683
692
  allow_pickle: bool = False,
684
693
  ) -> list[np.ndarray]:
685
694
  """
@@ -17,7 +17,7 @@ import os
17
17
  import pathlib
18
18
  import tempfile
19
19
  from abc import ABC, abstractmethod
20
- from typing import Any, Union
20
+ from typing import Any, Optional, Union
21
21
 
22
22
  import pandas as pd
23
23
 
@@ -56,7 +56,7 @@ class _Formatter(ABC):
56
56
  @classmethod
57
57
  @abstractmethod
58
58
  def read(
59
- cls, file_path: str, unflatten_kwargs: dict = None, **read_kwargs
59
+ cls, file_path: str, unflatten_kwargs: Optional[dict] = None, **read_kwargs
60
60
  ) -> pd.DataFrame:
61
61
  """
62
62
  Read the dataframe from the given file path.
@@ -173,7 +173,7 @@ class _ParquetFormatter(_Formatter):
173
173
 
174
174
  @classmethod
175
175
  def read(
176
- cls, file_path: str, unflatten_kwargs: dict = None, **read_kwargs
176
+ cls, file_path: str, unflatten_kwargs: Optional[dict] = None, **read_kwargs
177
177
  ) -> pd.DataFrame:
178
178
  """
179
179
  Read the dataframe from the given parquet file path.
@@ -221,7 +221,7 @@ class _CSVFormatter(_Formatter):
221
221
 
222
222
  @classmethod
223
223
  def read(
224
- cls, file_path: str, unflatten_kwargs: dict = None, **read_kwargs
224
+ cls, file_path: str, unflatten_kwargs: Optional[dict] = None, **read_kwargs
225
225
  ) -> pd.DataFrame:
226
226
  """
227
227
  Read the dataframe from the given csv file path.
@@ -275,7 +275,7 @@ class _H5Formatter(_Formatter):
275
275
 
276
276
  @classmethod
277
277
  def read(
278
- cls, file_path: str, unflatten_kwargs: dict = None, **read_kwargs
278
+ cls, file_path: str, unflatten_kwargs: Optional[dict] = None, **read_kwargs
279
279
  ) -> pd.DataFrame:
280
280
  """
281
281
  Read the dataframe from the given h5 file path.
@@ -332,7 +332,7 @@ class _XMLFormatter(_Formatter):
332
332
 
333
333
  @classmethod
334
334
  def read(
335
- cls, file_path: str, unflatten_kwargs: dict = None, **read_kwargs
335
+ cls, file_path: str, unflatten_kwargs: Optional[dict] = None, **read_kwargs
336
336
  ) -> pd.DataFrame:
337
337
  """
338
338
  Read the dataframe from the given xml file path.
@@ -391,7 +391,7 @@ class _XLSXFormatter(_Formatter):
391
391
 
392
392
  @classmethod
393
393
  def read(
394
- cls, file_path: str, unflatten_kwargs: dict = None, **read_kwargs
394
+ cls, file_path: str, unflatten_kwargs: Optional[dict] = None, **read_kwargs
395
395
  ) -> pd.DataFrame:
396
396
  """
397
397
  Read the dataframe from the given xlsx file path.
@@ -449,7 +449,7 @@ class _HTMLFormatter(_Formatter):
449
449
 
450
450
  @classmethod
451
451
  def read(
452
- cls, file_path: str, unflatten_kwargs: dict = None, **read_kwargs
452
+ cls, file_path: str, unflatten_kwargs: Optional[dict] = None, **read_kwargs
453
453
  ) -> pd.DataFrame:
454
454
  """
455
455
  Read dataframes from the given html file path.
@@ -510,7 +510,7 @@ class _JSONFormatter(_Formatter):
510
510
 
511
511
  @classmethod
512
512
  def read(
513
- cls, file_path: str, unflatten_kwargs: dict = None, **read_kwargs
513
+ cls, file_path: str, unflatten_kwargs: Optional[dict] = None, **read_kwargs
514
514
  ) -> pd.DataFrame:
515
515
  """
516
516
  Read dataframes from the given json file path.
@@ -565,7 +565,7 @@ class _FeatherFormatter(_Formatter):
565
565
 
566
566
  @classmethod
567
567
  def read(
568
- cls, file_path: str, unflatten_kwargs: dict = None, **read_kwargs
568
+ cls, file_path: str, unflatten_kwargs: Optional[dict] = None, **read_kwargs
569
569
  ) -> pd.DataFrame:
570
570
  """
571
571
  Read dataframes from the given feather file path.
@@ -620,7 +620,7 @@ class _ORCFormatter(_Formatter):
620
620
 
621
621
  @classmethod
622
622
  def read(
623
- cls, file_path: str, unflatten_kwargs: dict = None, **read_kwargs
623
+ cls, file_path: str, unflatten_kwargs: Optional[dict] = None, **read_kwargs
624
624
  ) -> pd.DataFrame:
625
625
  """
626
626
  Read dataframes from the given orc file path.
@@ -730,7 +730,7 @@ class PandasDataFramePackager(DefaultPackager):
730
730
  self,
731
731
  obj: pd.DataFrame,
732
732
  key: str,
733
- file_format: str = None,
733
+ file_format: Optional[str] = None,
734
734
  flatten: bool = True,
735
735
  **to_kwargs,
736
736
  ) -> tuple[Artifact, dict]:
@@ -785,8 +785,8 @@ class PandasDataFramePackager(DefaultPackager):
785
785
  def unpack_file(
786
786
  self,
787
787
  data_item: DataItem,
788
- file_format: str = None,
789
- read_kwargs: dict = None,
788
+ file_format: Optional[str] = None,
789
+ read_kwargs: Optional[dict] = None,
790
790
  ) -> pd.DataFrame:
791
791
  """
792
792
  Unpack a pandas dataframe from file.
@@ -883,7 +883,7 @@ class PandasSeriesPackager(PandasDataFramePackager):
883
883
  self,
884
884
  obj: pd.Series,
885
885
  key: str,
886
- file_format: str = None,
886
+ file_format: Optional[str] = None,
887
887
  flatten: bool = True,
888
888
  **to_kwargs,
889
889
  ) -> tuple[Artifact, dict]:
@@ -919,9 +919,9 @@ class PandasSeriesPackager(PandasDataFramePackager):
919
919
  def unpack_file(
920
920
  self,
921
921
  data_item: DataItem,
922
- file_format: str = None,
923
- read_kwargs: dict = None,
924
- column_name: Union[str, int] = None,
922
+ file_format: Optional[str] = None,
923
+ read_kwargs: Optional[dict] = None,
924
+ column_name: Optional[Union[str, int]] = None,
925
925
  ) -> pd.Series:
926
926
  """
927
927
  Unpack a pandas series from file.