mlrun 1.7.2__py3-none-any.whl → 1.8.0rc1__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 (222) hide show
  1. mlrun/__init__.py +14 -12
  2. mlrun/__main__.py +3 -3
  3. mlrun/alerts/alert.py +19 -12
  4. mlrun/artifacts/__init__.py +0 -2
  5. mlrun/artifacts/base.py +34 -11
  6. mlrun/artifacts/dataset.py +16 -16
  7. mlrun/artifacts/manager.py +13 -13
  8. mlrun/artifacts/model.py +66 -53
  9. mlrun/common/constants.py +6 -0
  10. mlrun/common/formatters/__init__.py +1 -0
  11. mlrun/common/formatters/feature_set.py +1 -0
  12. mlrun/common/formatters/function.py +1 -0
  13. mlrun/common/formatters/model_endpoint.py +30 -0
  14. mlrun/common/formatters/pipeline.py +1 -2
  15. mlrun/common/model_monitoring/__init__.py +0 -3
  16. mlrun/common/model_monitoring/helpers.py +1 -1
  17. mlrun/common/runtimes/constants.py +1 -2
  18. mlrun/common/schemas/__init__.py +4 -2
  19. mlrun/common/schemas/artifact.py +0 -6
  20. mlrun/common/schemas/common.py +50 -0
  21. mlrun/common/schemas/model_monitoring/__init__.py +8 -1
  22. mlrun/common/schemas/model_monitoring/constants.py +62 -12
  23. mlrun/common/schemas/model_monitoring/model_endpoint_v2.py +149 -0
  24. mlrun/common/schemas/model_monitoring/model_endpoints.py +21 -5
  25. mlrun/common/schemas/partition.py +122 -0
  26. mlrun/config.py +43 -15
  27. mlrun/data_types/__init__.py +0 -2
  28. mlrun/data_types/data_types.py +0 -1
  29. mlrun/data_types/infer.py +3 -1
  30. mlrun/data_types/spark.py +4 -4
  31. mlrun/data_types/to_pandas.py +2 -11
  32. mlrun/datastore/__init__.py +0 -2
  33. mlrun/datastore/alibaba_oss.py +4 -1
  34. mlrun/datastore/azure_blob.py +4 -1
  35. mlrun/datastore/base.py +12 -4
  36. mlrun/datastore/datastore.py +9 -3
  37. mlrun/datastore/datastore_profile.py +1 -1
  38. mlrun/datastore/dbfs_store.py +4 -1
  39. mlrun/datastore/filestore.py +4 -1
  40. mlrun/datastore/google_cloud_storage.py +4 -1
  41. mlrun/datastore/hdfs.py +4 -1
  42. mlrun/datastore/inmem.py +4 -1
  43. mlrun/datastore/redis.py +4 -1
  44. mlrun/datastore/s3.py +4 -1
  45. mlrun/datastore/sources.py +51 -49
  46. mlrun/datastore/store_resources.py +0 -2
  47. mlrun/datastore/targets.py +22 -23
  48. mlrun/datastore/utils.py +2 -2
  49. mlrun/datastore/v3io.py +4 -1
  50. mlrun/datastore/wasbfs/fs.py +13 -12
  51. mlrun/db/base.py +126 -62
  52. mlrun/db/factory.py +3 -0
  53. mlrun/db/httpdb.py +767 -231
  54. mlrun/db/nopdb.py +126 -57
  55. mlrun/errors.py +2 -2
  56. mlrun/execution.py +55 -29
  57. mlrun/feature_store/__init__.py +0 -2
  58. mlrun/feature_store/api.py +40 -40
  59. mlrun/feature_store/common.py +9 -9
  60. mlrun/feature_store/feature_set.py +20 -18
  61. mlrun/feature_store/feature_vector.py +27 -24
  62. mlrun/feature_store/retrieval/base.py +14 -9
  63. mlrun/feature_store/retrieval/job.py +2 -1
  64. mlrun/feature_store/steps.py +2 -2
  65. mlrun/features.py +30 -13
  66. mlrun/frameworks/__init__.py +1 -2
  67. mlrun/frameworks/_common/__init__.py +1 -2
  68. mlrun/frameworks/_common/artifacts_library.py +2 -2
  69. mlrun/frameworks/_common/mlrun_interface.py +10 -6
  70. mlrun/frameworks/_common/model_handler.py +29 -27
  71. mlrun/frameworks/_common/producer.py +3 -1
  72. mlrun/frameworks/_dl_common/__init__.py +1 -2
  73. mlrun/frameworks/_dl_common/loggers/__init__.py +1 -2
  74. mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +4 -4
  75. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +3 -3
  76. mlrun/frameworks/_ml_common/__init__.py +1 -2
  77. mlrun/frameworks/_ml_common/loggers/__init__.py +1 -2
  78. mlrun/frameworks/_ml_common/model_handler.py +21 -21
  79. mlrun/frameworks/_ml_common/plans/__init__.py +1 -2
  80. mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +3 -1
  81. mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
  82. mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
  83. mlrun/frameworks/auto_mlrun/__init__.py +1 -2
  84. mlrun/frameworks/auto_mlrun/auto_mlrun.py +22 -15
  85. mlrun/frameworks/huggingface/__init__.py +1 -2
  86. mlrun/frameworks/huggingface/model_server.py +9 -9
  87. mlrun/frameworks/lgbm/__init__.py +47 -44
  88. mlrun/frameworks/lgbm/callbacks/__init__.py +1 -2
  89. mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -2
  90. mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -2
  91. mlrun/frameworks/lgbm/mlrun_interfaces/__init__.py +1 -2
  92. mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +5 -5
  93. mlrun/frameworks/lgbm/model_handler.py +15 -11
  94. mlrun/frameworks/lgbm/model_server.py +11 -7
  95. mlrun/frameworks/lgbm/utils.py +2 -2
  96. mlrun/frameworks/onnx/__init__.py +1 -2
  97. mlrun/frameworks/onnx/dataset.py +3 -3
  98. mlrun/frameworks/onnx/mlrun_interface.py +2 -2
  99. mlrun/frameworks/onnx/model_handler.py +7 -5
  100. mlrun/frameworks/onnx/model_server.py +8 -6
  101. mlrun/frameworks/parallel_coordinates.py +11 -11
  102. mlrun/frameworks/pytorch/__init__.py +22 -23
  103. mlrun/frameworks/pytorch/callbacks/__init__.py +1 -2
  104. mlrun/frameworks/pytorch/callbacks/callback.py +2 -1
  105. mlrun/frameworks/pytorch/callbacks/logging_callback.py +15 -8
  106. mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +19 -12
  107. mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +22 -15
  108. mlrun/frameworks/pytorch/callbacks_handler.py +36 -30
  109. mlrun/frameworks/pytorch/mlrun_interface.py +17 -17
  110. mlrun/frameworks/pytorch/model_handler.py +21 -17
  111. mlrun/frameworks/pytorch/model_server.py +13 -9
  112. mlrun/frameworks/sklearn/__init__.py +19 -18
  113. mlrun/frameworks/sklearn/estimator.py +2 -2
  114. mlrun/frameworks/sklearn/metric.py +3 -3
  115. mlrun/frameworks/sklearn/metrics_library.py +8 -6
  116. mlrun/frameworks/sklearn/mlrun_interface.py +3 -2
  117. mlrun/frameworks/sklearn/model_handler.py +4 -3
  118. mlrun/frameworks/tf_keras/__init__.py +11 -12
  119. mlrun/frameworks/tf_keras/callbacks/__init__.py +1 -2
  120. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +17 -14
  121. mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +15 -12
  122. mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +21 -18
  123. mlrun/frameworks/tf_keras/model_handler.py +17 -13
  124. mlrun/frameworks/tf_keras/model_server.py +12 -8
  125. mlrun/frameworks/xgboost/__init__.py +19 -18
  126. mlrun/frameworks/xgboost/model_handler.py +13 -9
  127. mlrun/launcher/base.py +3 -4
  128. mlrun/launcher/local.py +1 -1
  129. mlrun/launcher/remote.py +1 -1
  130. mlrun/lists.py +4 -3
  131. mlrun/model.py +108 -44
  132. mlrun/model_monitoring/__init__.py +1 -2
  133. mlrun/model_monitoring/api.py +6 -6
  134. mlrun/model_monitoring/applications/_application_steps.py +13 -15
  135. mlrun/model_monitoring/applications/histogram_data_drift.py +41 -15
  136. mlrun/model_monitoring/applications/results.py +55 -3
  137. mlrun/model_monitoring/controller.py +185 -223
  138. mlrun/model_monitoring/db/_schedules.py +156 -0
  139. mlrun/model_monitoring/db/_stats.py +189 -0
  140. mlrun/model_monitoring/db/stores/__init__.py +1 -1
  141. mlrun/model_monitoring/db/stores/base/store.py +6 -65
  142. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -25
  143. mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -97
  144. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +2 -58
  145. mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -15
  146. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +6 -257
  147. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +9 -271
  148. mlrun/model_monitoring/db/tsdb/base.py +74 -22
  149. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +66 -35
  150. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +33 -0
  151. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +284 -51
  152. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +1 -0
  153. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +35 -17
  154. mlrun/model_monitoring/helpers.py +97 -1
  155. mlrun/model_monitoring/model_endpoint.py +4 -2
  156. mlrun/model_monitoring/stream_processing.py +2 -2
  157. mlrun/model_monitoring/tracking_policy.py +10 -3
  158. mlrun/model_monitoring/writer.py +47 -26
  159. mlrun/package/__init__.py +3 -6
  160. mlrun/package/context_handler.py +1 -1
  161. mlrun/package/packager.py +12 -9
  162. mlrun/package/packagers/__init__.py +0 -2
  163. mlrun/package/packagers/default_packager.py +14 -11
  164. mlrun/package/packagers/numpy_packagers.py +16 -7
  165. mlrun/package/packagers/pandas_packagers.py +18 -18
  166. mlrun/package/packagers/python_standard_library_packagers.py +25 -11
  167. mlrun/package/packagers_manager.py +31 -14
  168. mlrun/package/utils/__init__.py +0 -3
  169. mlrun/package/utils/_pickler.py +6 -6
  170. mlrun/platforms/__init__.py +3 -3
  171. mlrun/platforms/iguazio.py +4 -1
  172. mlrun/projects/__init__.py +1 -6
  173. mlrun/projects/operations.py +27 -27
  174. mlrun/projects/pipelines.py +85 -215
  175. mlrun/projects/project.py +444 -158
  176. mlrun/run.py +9 -9
  177. mlrun/runtimes/__init__.py +1 -3
  178. mlrun/runtimes/base.py +13 -10
  179. mlrun/runtimes/daskjob.py +9 -9
  180. mlrun/runtimes/generators.py +2 -1
  181. mlrun/runtimes/kubejob.py +4 -5
  182. mlrun/runtimes/mpijob/__init__.py +0 -2
  183. mlrun/runtimes/mpijob/abstract.py +7 -6
  184. mlrun/runtimes/nuclio/api_gateway.py +7 -7
  185. mlrun/runtimes/nuclio/application/application.py +11 -11
  186. mlrun/runtimes/nuclio/function.py +14 -14
  187. mlrun/runtimes/nuclio/serving.py +9 -9
  188. mlrun/runtimes/pod.py +74 -29
  189. mlrun/runtimes/remotesparkjob.py +3 -2
  190. mlrun/runtimes/sparkjob/__init__.py +0 -2
  191. mlrun/runtimes/sparkjob/spark3job.py +21 -11
  192. mlrun/runtimes/utils.py +6 -5
  193. mlrun/serving/merger.py +6 -4
  194. mlrun/serving/remote.py +18 -17
  195. mlrun/serving/routers.py +27 -27
  196. mlrun/serving/server.py +1 -1
  197. mlrun/serving/states.py +76 -71
  198. mlrun/serving/utils.py +13 -2
  199. mlrun/serving/v1_serving.py +3 -2
  200. mlrun/serving/v2_serving.py +4 -4
  201. mlrun/track/__init__.py +1 -1
  202. mlrun/track/tracker.py +2 -2
  203. mlrun/track/trackers/mlflow_tracker.py +6 -5
  204. mlrun/utils/async_http.py +1 -1
  205. mlrun/utils/helpers.py +72 -28
  206. mlrun/utils/logger.py +104 -2
  207. mlrun/utils/notifications/notification/base.py +23 -4
  208. mlrun/utils/notifications/notification/console.py +1 -1
  209. mlrun/utils/notifications/notification/git.py +6 -6
  210. mlrun/utils/notifications/notification/ipython.py +5 -4
  211. mlrun/utils/notifications/notification/slack.py +1 -1
  212. mlrun/utils/notifications/notification/webhook.py +13 -17
  213. mlrun/utils/notifications/notification_pusher.py +23 -19
  214. mlrun/utils/regex.py +1 -1
  215. mlrun/utils/version/version.json +2 -2
  216. {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/METADATA +187 -199
  217. mlrun-1.8.0rc1.dist-info/RECORD +356 -0
  218. {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/WHEEL +1 -1
  219. mlrun-1.7.2.dist-info/RECORD +0 -351
  220. {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/LICENSE +0 -0
  221. {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/entry_points.txt +0 -0
  222. {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/top_level.txt +0 -0
@@ -13,6 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import datetime
16
+ import os
16
17
  import typing
17
18
 
18
19
  import numpy as np
@@ -27,7 +28,9 @@ import mlrun.artifacts
27
28
  import mlrun.common.model_monitoring.helpers
28
29
  import mlrun.common.schemas.model_monitoring.constants as mm_constants
29
30
  import mlrun.data_types.infer
31
+ import mlrun.datastore
30
32
  import mlrun.model_monitoring
33
+ import mlrun.utils.helpers
31
34
  from mlrun.common.schemas.model_monitoring.model_endpoints import (
32
35
  ModelEndpointMonitoringMetric,
33
36
  _compose_full_name,
@@ -98,7 +101,74 @@ def get_monitoring_parquet_path(
98
101
  return parquet_path
99
102
 
100
103
 
101
- def get_connection_string(secret_provider: typing.Callable[[str], str] = None) -> str:
104
+ def get_monitoring_stats_directory_path(
105
+ project: str,
106
+ kind: str = mm_constants.FileTargetKind.STATS,
107
+ ) -> str:
108
+ """
109
+ Get model monitoring stats target for the current project and kind. The stats target path is based on the
110
+ project artifact path. If project artifact path is not defined, the stats target path will be based on MLRun
111
+ artifact path.
112
+ :param project: Project object.
113
+ :param kind: indicate the kind of the stats path
114
+ :return: Monitoring stats target path.
115
+ """
116
+ stats_path = mlrun.mlconf.get_model_monitoring_file_target_path(
117
+ project=project,
118
+ kind=kind,
119
+ )
120
+ return stats_path
121
+
122
+
123
+ def _get_monitoring_current_stats_file_path(project: str, endpoint_id: str) -> str:
124
+ return os.path.join(
125
+ get_monitoring_stats_directory_path(project),
126
+ f"{endpoint_id}_current_stats.json",
127
+ )
128
+
129
+
130
+ def _get_monitoring_drift_measures_file_path(project: str, endpoint_id: str) -> str:
131
+ return os.path.join(
132
+ get_monitoring_stats_directory_path(project),
133
+ f"{endpoint_id}_drift_measures.json",
134
+ )
135
+
136
+
137
+ def get_monitoring_current_stats_data(
138
+ project: str, endpoint_id: str
139
+ ) -> mlrun.datastore.DataItem:
140
+ """
141
+ getter for data item of current stats for project and endpoint
142
+ :param project: project name str
143
+ :param endpoint_id: endpoint id str
144
+ :return: DataItem
145
+ """
146
+ return mlrun.datastore.store_manager.object(
147
+ _get_monitoring_current_stats_file_path(
148
+ project=project, endpoint_id=endpoint_id
149
+ )
150
+ )
151
+
152
+
153
+ def get_monitoring_drift_measures_data(
154
+ project: str, endpoint_id: str
155
+ ) -> mlrun.datastore.DataItem:
156
+ """
157
+ getter for data item of drift measures for project and endpoint
158
+ :param project: project name str
159
+ :param endpoint_id: endpoint id str
160
+ :return: DataItem
161
+ """
162
+ return mlrun.datastore.store_manager.object(
163
+ _get_monitoring_drift_measures_file_path(
164
+ project=project, endpoint_id=endpoint_id
165
+ )
166
+ )
167
+
168
+
169
+ def get_connection_string(
170
+ secret_provider: typing.Optional[typing.Callable[[str], str]] = None,
171
+ ) -> str:
102
172
  """Get endpoint store connection string from the project secret. If wasn't set, take it from the system
103
173
  configurations.
104
174
 
@@ -350,3 +420,29 @@ def enrich_model_endpoint_with_model_uri(
350
420
  model_endpoint.spec.model_uri = mlrun.datastore.get_store_uri(
351
421
  kind=mlrun.utils.helpers.StorePrefix.Model, uri=model_artifact_uri
352
422
  )
423
+
424
+
425
+ def _get_monitoring_schedules_folder_path(project: str) -> str:
426
+ return typing.cast(
427
+ str,
428
+ mlrun.mlconf.get_model_monitoring_file_target_path(
429
+ project=project, kind=mm_constants.FileTargetKind.MONITORING_SCHEDULES
430
+ ),
431
+ )
432
+
433
+
434
+ def _get_monitoring_schedules_file_path(*, project: str, endpoint_id: str) -> str:
435
+ return os.path.join(
436
+ _get_monitoring_schedules_folder_path(project), f"{endpoint_id}.json"
437
+ )
438
+
439
+
440
+ def get_monitoring_schedules_data(
441
+ *, project: str, endpoint_id: str
442
+ ) -> mlrun.datastore.DataItem:
443
+ """
444
+ Get the model monitoring schedules' data item of the project's model endpoint.
445
+ """
446
+ return mlrun.datastore.store_manager.object(
447
+ _get_monitoring_schedules_file_path(project=project, endpoint_id=endpoint_id)
448
+ )
@@ -14,7 +14,7 @@
14
14
  #
15
15
 
16
16
  from dataclasses import dataclass, field
17
- from typing import Any
17
+ from typing import Any, Optional
18
18
 
19
19
  import mlrun.model
20
20
  from mlrun.common.model_monitoring.helpers import FeatureStats
@@ -104,7 +104,9 @@ class ModelEndpoint(mlrun.model.ModelObj):
104
104
  )
105
105
 
106
106
  @classmethod
107
- def from_flat_dict(cls, struct=None, fields=None, deprecated_fields: dict = None):
107
+ def from_flat_dict(
108
+ cls, struct=None, fields=None, deprecated_fields: Optional[dict] = None
109
+ ):
108
110
  new_obj = cls()
109
111
  new_obj._metadata = mlrun.model.VersionedObjMetadata().from_dict(
110
112
  struct=struct, fields=fields, deprecated_fields=deprecated_fields
@@ -51,7 +51,7 @@ class EventStreamProcessor:
51
51
  parquet_target: str,
52
52
  aggregate_windows: typing.Optional[list[str]] = None,
53
53
  aggregate_period: str = "5m",
54
- model_monitoring_access_key: str = None,
54
+ model_monitoring_access_key: typing.Optional[str] = None,
55
55
  ):
56
56
  # General configurations, mainly used for the storey steps in the future serving graph
57
57
  self.project = project
@@ -85,7 +85,7 @@ class EventStreamProcessor:
85
85
  v3io_access_key: typing.Optional[str] = None,
86
86
  v3io_framesd: typing.Optional[str] = None,
87
87
  v3io_api: typing.Optional[str] = None,
88
- model_monitoring_access_key: str = None,
88
+ model_monitoring_access_key: typing.Optional[str] = None,
89
89
  ):
90
90
  # Get the V3IO configurations
91
91
  self.v3io_framesd = v3io_framesd or mlrun.mlconf.v3io_framesd
@@ -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
@@ -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,7 +13,8 @@
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
@@ -26,10 +27,16 @@ from mlrun.common.schemas.model_monitoring.constants import (
26
27
  ResultData,
27
28
  ResultKindApp,
28
29
  ResultStatusApp,
30
+ StatsData,
31
+ StatsKind,
29
32
  WriterEvent,
30
33
  WriterEventKind,
31
34
  )
32
35
  from mlrun.common.schemas.notification import NotificationKind, NotificationSeverity
36
+ from mlrun.model_monitoring.db._stats import (
37
+ ModelMonitoringCurrentStatsFile,
38
+ ModelMonitoringDriftMeasuresFile,
39
+ )
33
40
  from mlrun.model_monitoring.helpers import get_result_instance_fqn
34
41
  from mlrun.serving.utils import StepToDict
35
42
  from mlrun.utils import logger
@@ -105,7 +112,7 @@ class ModelMonitoringWriter(StepToDict):
105
112
  def __init__(
106
113
  self,
107
114
  project: str,
108
- secret_provider: Callable = None,
115
+ secret_provider: Optional[Callable] = None,
109
116
  ) -> None:
110
117
  self.project = project
111
118
  self.name = project # required for the deployment process
@@ -190,6 +197,8 @@ class ModelMonitoringWriter(StepToDict):
190
197
  expected_keys.extend(MetricData.list())
191
198
  elif kind == WriterEventKind.RESULT:
192
199
  expected_keys.extend(ResultData.list())
200
+ elif kind == WriterEventKind.STATS:
201
+ expected_keys.extend(StatsData.list())
193
202
  else:
194
203
  raise _WriterEventValueError(
195
204
  f"Unknown event kind: {kind}, expected one of: {WriterEventKind.list()}"
@@ -198,16 +207,50 @@ class ModelMonitoringWriter(StepToDict):
198
207
  if missing_keys:
199
208
  raise _WriterEventValueError(
200
209
  f"The received event misses some keys compared to the expected "
201
- f"monitoring application event schema: {missing_keys}"
210
+ f"monitoring application event schema: {missing_keys} for event kind {kind}"
202
211
  )
203
212
 
204
213
  return result_event, kind
205
214
 
215
+ def write_stats(self, event: _AppResultEvent) -> None:
216
+ """
217
+ Write to file the application stats event
218
+ :param event: application stats event
219
+ """
220
+ endpoint_id = event[WriterEvent.ENDPOINT_ID]
221
+ logger.debug(
222
+ "Updating the model endpoint with stats",
223
+ endpoint_id=endpoint_id,
224
+ )
225
+ stat_kind = event.get(StatsData.STATS_NAME)
226
+ data, timestamp_str = event.get(StatsData.STATS), event.get(StatsData.TIMESTAMP)
227
+ timestamp = datetime.fromisoformat(timestamp_str).astimezone(tz=timezone.utc)
228
+ if stat_kind == StatsKind.CURRENT_STATS.value:
229
+ ModelMonitoringCurrentStatsFile(self.project, endpoint_id).write(
230
+ data, timestamp
231
+ )
232
+ elif stat_kind == StatsKind.DRIFT_MEASURES.value:
233
+ ModelMonitoringDriftMeasuresFile(self.project, endpoint_id).write(
234
+ data, timestamp
235
+ )
236
+ logger.info(
237
+ "Updating the model endpoint statistics",
238
+ endpoint_id=endpoint_id,
239
+ stats_kind=stat_kind,
240
+ )
241
+
206
242
  def do(self, event: _RawEvent) -> None:
207
243
  event, kind = self._reconstruct_event(event)
208
244
  logger.info("Starting to write event", event=event)
245
+ if (
246
+ kind == WriterEventKind.STATS
247
+ and event[WriterEvent.APPLICATION_NAME]
248
+ == HistogramDataDriftApplicationConstants.NAME
249
+ ):
250
+ self.write_stats(event)
251
+ logger.info("Model monitoring writer finished handling event")
252
+ return
209
253
  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
254
 
212
255
  logger.info("Completed event DB writes")
213
256
 
@@ -247,26 +290,4 @@ class ModelMonitoringWriter(StepToDict):
247
290
  result_kind=event[ResultData.RESULT_KIND],
248
291
  )
249
292
 
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
293
  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
  """
@@ -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
  """