mlrun 1.7.1rc4__py3-none-any.whl → 1.8.0rc8__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 (257) hide show
  1. mlrun/__init__.py +23 -21
  2. mlrun/__main__.py +3 -3
  3. mlrun/alerts/alert.py +148 -14
  4. mlrun/artifacts/__init__.py +1 -2
  5. mlrun/artifacts/base.py +46 -12
  6. mlrun/artifacts/dataset.py +16 -16
  7. mlrun/artifacts/document.py +334 -0
  8. mlrun/artifacts/manager.py +15 -13
  9. mlrun/artifacts/model.py +66 -53
  10. mlrun/common/constants.py +7 -0
  11. mlrun/common/formatters/__init__.py +1 -0
  12. mlrun/common/formatters/feature_set.py +1 -0
  13. mlrun/common/formatters/function.py +1 -0
  14. mlrun/{model_monitoring/db/stores/base/__init__.py → common/formatters/model_endpoint.py} +16 -1
  15. mlrun/common/formatters/pipeline.py +1 -2
  16. mlrun/common/formatters/project.py +9 -0
  17. mlrun/common/model_monitoring/__init__.py +0 -5
  18. mlrun/common/model_monitoring/helpers.py +1 -29
  19. mlrun/common/runtimes/constants.py +1 -2
  20. mlrun/common/schemas/__init__.py +6 -2
  21. mlrun/common/schemas/alert.py +111 -19
  22. mlrun/common/schemas/api_gateway.py +3 -3
  23. mlrun/common/schemas/artifact.py +11 -7
  24. mlrun/common/schemas/auth.py +6 -4
  25. mlrun/common/schemas/background_task.py +7 -7
  26. mlrun/common/schemas/client_spec.py +2 -3
  27. mlrun/common/schemas/clusterization_spec.py +2 -2
  28. mlrun/common/schemas/common.py +53 -3
  29. mlrun/common/schemas/constants.py +15 -0
  30. mlrun/common/schemas/datastore_profile.py +1 -1
  31. mlrun/common/schemas/feature_store.py +9 -9
  32. mlrun/common/schemas/frontend_spec.py +4 -4
  33. mlrun/common/schemas/function.py +10 -10
  34. mlrun/common/schemas/hub.py +1 -1
  35. mlrun/common/schemas/k8s.py +3 -3
  36. mlrun/common/schemas/memory_reports.py +3 -3
  37. mlrun/common/schemas/model_monitoring/__init__.py +2 -1
  38. mlrun/common/schemas/model_monitoring/constants.py +66 -14
  39. mlrun/common/schemas/model_monitoring/grafana.py +1 -1
  40. mlrun/common/schemas/model_monitoring/model_endpoints.py +91 -147
  41. mlrun/common/schemas/notification.py +24 -3
  42. mlrun/common/schemas/object.py +1 -1
  43. mlrun/common/schemas/pagination.py +4 -4
  44. mlrun/common/schemas/partition.py +137 -0
  45. mlrun/common/schemas/pipeline.py +2 -2
  46. mlrun/common/schemas/project.py +25 -17
  47. mlrun/common/schemas/runs.py +2 -2
  48. mlrun/common/schemas/runtime_resource.py +5 -5
  49. mlrun/common/schemas/schedule.py +1 -1
  50. mlrun/common/schemas/secret.py +1 -1
  51. mlrun/common/schemas/tag.py +3 -3
  52. mlrun/common/schemas/workflow.py +5 -5
  53. mlrun/config.py +67 -10
  54. mlrun/data_types/__init__.py +0 -2
  55. mlrun/data_types/infer.py +3 -1
  56. mlrun/data_types/spark.py +2 -1
  57. mlrun/datastore/__init__.py +0 -2
  58. mlrun/datastore/alibaba_oss.py +4 -1
  59. mlrun/datastore/azure_blob.py +4 -1
  60. mlrun/datastore/base.py +12 -4
  61. mlrun/datastore/datastore.py +9 -3
  62. mlrun/datastore/datastore_profile.py +79 -20
  63. mlrun/datastore/dbfs_store.py +4 -1
  64. mlrun/datastore/filestore.py +4 -1
  65. mlrun/datastore/google_cloud_storage.py +4 -1
  66. mlrun/datastore/hdfs.py +4 -1
  67. mlrun/datastore/inmem.py +4 -1
  68. mlrun/datastore/redis.py +4 -1
  69. mlrun/datastore/s3.py +4 -1
  70. mlrun/datastore/sources.py +52 -51
  71. mlrun/datastore/store_resources.py +0 -2
  72. mlrun/datastore/targets.py +21 -21
  73. mlrun/datastore/utils.py +2 -2
  74. mlrun/datastore/v3io.py +4 -1
  75. mlrun/datastore/vectorstore.py +194 -0
  76. mlrun/datastore/wasbfs/fs.py +13 -12
  77. mlrun/db/base.py +208 -82
  78. mlrun/db/factory.py +0 -3
  79. mlrun/db/httpdb.py +1237 -386
  80. mlrun/db/nopdb.py +201 -74
  81. mlrun/errors.py +2 -2
  82. mlrun/execution.py +136 -50
  83. mlrun/feature_store/__init__.py +0 -2
  84. mlrun/feature_store/api.py +41 -40
  85. mlrun/feature_store/common.py +9 -9
  86. mlrun/feature_store/feature_set.py +20 -18
  87. mlrun/feature_store/feature_vector.py +27 -24
  88. mlrun/feature_store/retrieval/base.py +14 -9
  89. mlrun/feature_store/retrieval/job.py +2 -1
  90. mlrun/feature_store/steps.py +2 -2
  91. mlrun/features.py +30 -13
  92. mlrun/frameworks/__init__.py +1 -2
  93. mlrun/frameworks/_common/__init__.py +1 -2
  94. mlrun/frameworks/_common/artifacts_library.py +2 -2
  95. mlrun/frameworks/_common/mlrun_interface.py +10 -6
  96. mlrun/frameworks/_common/model_handler.py +29 -27
  97. mlrun/frameworks/_common/producer.py +3 -1
  98. mlrun/frameworks/_dl_common/__init__.py +1 -2
  99. mlrun/frameworks/_dl_common/loggers/__init__.py +1 -2
  100. mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +4 -4
  101. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +3 -3
  102. mlrun/frameworks/_ml_common/__init__.py +1 -2
  103. mlrun/frameworks/_ml_common/loggers/__init__.py +1 -2
  104. mlrun/frameworks/_ml_common/model_handler.py +21 -21
  105. mlrun/frameworks/_ml_common/plans/__init__.py +1 -2
  106. mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +3 -1
  107. mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
  108. mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
  109. mlrun/frameworks/auto_mlrun/__init__.py +1 -2
  110. mlrun/frameworks/auto_mlrun/auto_mlrun.py +22 -15
  111. mlrun/frameworks/huggingface/__init__.py +1 -2
  112. mlrun/frameworks/huggingface/model_server.py +9 -9
  113. mlrun/frameworks/lgbm/__init__.py +47 -44
  114. mlrun/frameworks/lgbm/callbacks/__init__.py +1 -2
  115. mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -2
  116. mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -2
  117. mlrun/frameworks/lgbm/mlrun_interfaces/__init__.py +1 -2
  118. mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +5 -5
  119. mlrun/frameworks/lgbm/model_handler.py +15 -11
  120. mlrun/frameworks/lgbm/model_server.py +11 -7
  121. mlrun/frameworks/lgbm/utils.py +2 -2
  122. mlrun/frameworks/onnx/__init__.py +1 -2
  123. mlrun/frameworks/onnx/dataset.py +3 -3
  124. mlrun/frameworks/onnx/mlrun_interface.py +2 -2
  125. mlrun/frameworks/onnx/model_handler.py +7 -5
  126. mlrun/frameworks/onnx/model_server.py +8 -6
  127. mlrun/frameworks/parallel_coordinates.py +11 -11
  128. mlrun/frameworks/pytorch/__init__.py +22 -23
  129. mlrun/frameworks/pytorch/callbacks/__init__.py +1 -2
  130. mlrun/frameworks/pytorch/callbacks/callback.py +2 -1
  131. mlrun/frameworks/pytorch/callbacks/logging_callback.py +15 -8
  132. mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +19 -12
  133. mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +22 -15
  134. mlrun/frameworks/pytorch/callbacks_handler.py +36 -30
  135. mlrun/frameworks/pytorch/mlrun_interface.py +17 -17
  136. mlrun/frameworks/pytorch/model_handler.py +21 -17
  137. mlrun/frameworks/pytorch/model_server.py +13 -9
  138. mlrun/frameworks/sklearn/__init__.py +19 -18
  139. mlrun/frameworks/sklearn/estimator.py +2 -2
  140. mlrun/frameworks/sklearn/metric.py +3 -3
  141. mlrun/frameworks/sklearn/metrics_library.py +8 -6
  142. mlrun/frameworks/sklearn/mlrun_interface.py +3 -2
  143. mlrun/frameworks/sklearn/model_handler.py +4 -3
  144. mlrun/frameworks/tf_keras/__init__.py +11 -12
  145. mlrun/frameworks/tf_keras/callbacks/__init__.py +1 -2
  146. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +17 -14
  147. mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +15 -12
  148. mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +21 -18
  149. mlrun/frameworks/tf_keras/model_handler.py +17 -13
  150. mlrun/frameworks/tf_keras/model_server.py +12 -8
  151. mlrun/frameworks/xgboost/__init__.py +19 -18
  152. mlrun/frameworks/xgboost/model_handler.py +13 -9
  153. mlrun/launcher/base.py +3 -4
  154. mlrun/launcher/local.py +1 -1
  155. mlrun/launcher/remote.py +1 -1
  156. mlrun/lists.py +4 -3
  157. mlrun/model.py +117 -46
  158. mlrun/model_monitoring/__init__.py +4 -4
  159. mlrun/model_monitoring/api.py +61 -59
  160. mlrun/model_monitoring/applications/_application_steps.py +17 -17
  161. mlrun/model_monitoring/applications/base.py +165 -6
  162. mlrun/model_monitoring/applications/context.py +88 -37
  163. mlrun/model_monitoring/applications/evidently_base.py +1 -2
  164. mlrun/model_monitoring/applications/histogram_data_drift.py +43 -21
  165. mlrun/model_monitoring/applications/results.py +55 -3
  166. mlrun/model_monitoring/controller.py +207 -239
  167. mlrun/model_monitoring/db/__init__.py +0 -2
  168. mlrun/model_monitoring/db/_schedules.py +156 -0
  169. mlrun/model_monitoring/db/_stats.py +189 -0
  170. mlrun/model_monitoring/db/tsdb/base.py +78 -25
  171. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +90 -16
  172. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +33 -0
  173. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +279 -59
  174. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +1 -0
  175. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +78 -17
  176. mlrun/model_monitoring/helpers.py +152 -49
  177. mlrun/model_monitoring/stream_processing.py +99 -283
  178. mlrun/model_monitoring/tracking_policy.py +10 -3
  179. mlrun/model_monitoring/writer.py +48 -36
  180. mlrun/package/__init__.py +3 -6
  181. mlrun/package/context_handler.py +1 -1
  182. mlrun/package/packager.py +12 -9
  183. mlrun/package/packagers/__init__.py +0 -2
  184. mlrun/package/packagers/default_packager.py +14 -11
  185. mlrun/package/packagers/numpy_packagers.py +16 -7
  186. mlrun/package/packagers/pandas_packagers.py +18 -18
  187. mlrun/package/packagers/python_standard_library_packagers.py +25 -11
  188. mlrun/package/packagers_manager.py +31 -14
  189. mlrun/package/utils/__init__.py +0 -3
  190. mlrun/package/utils/_pickler.py +6 -6
  191. mlrun/platforms/__init__.py +47 -16
  192. mlrun/platforms/iguazio.py +4 -1
  193. mlrun/projects/operations.py +27 -27
  194. mlrun/projects/pipelines.py +75 -38
  195. mlrun/projects/project.py +865 -206
  196. mlrun/run.py +53 -10
  197. mlrun/runtimes/__init__.py +1 -3
  198. mlrun/runtimes/base.py +15 -11
  199. mlrun/runtimes/daskjob.py +9 -9
  200. mlrun/runtimes/generators.py +2 -1
  201. mlrun/runtimes/kubejob.py +4 -5
  202. mlrun/runtimes/mounts.py +572 -0
  203. mlrun/runtimes/mpijob/__init__.py +0 -2
  204. mlrun/runtimes/mpijob/abstract.py +7 -6
  205. mlrun/runtimes/nuclio/api_gateway.py +7 -7
  206. mlrun/runtimes/nuclio/application/application.py +11 -11
  207. mlrun/runtimes/nuclio/function.py +19 -17
  208. mlrun/runtimes/nuclio/serving.py +18 -11
  209. mlrun/runtimes/pod.py +154 -45
  210. mlrun/runtimes/remotesparkjob.py +3 -2
  211. mlrun/runtimes/sparkjob/__init__.py +0 -2
  212. mlrun/runtimes/sparkjob/spark3job.py +21 -11
  213. mlrun/runtimes/utils.py +6 -5
  214. mlrun/serving/merger.py +6 -4
  215. mlrun/serving/remote.py +18 -17
  216. mlrun/serving/routers.py +185 -172
  217. mlrun/serving/server.py +7 -1
  218. mlrun/serving/states.py +97 -78
  219. mlrun/serving/utils.py +13 -2
  220. mlrun/serving/v1_serving.py +3 -2
  221. mlrun/serving/v2_serving.py +74 -65
  222. mlrun/track/__init__.py +1 -1
  223. mlrun/track/tracker.py +2 -2
  224. mlrun/track/trackers/mlflow_tracker.py +6 -5
  225. mlrun/utils/async_http.py +1 -1
  226. mlrun/utils/clones.py +1 -1
  227. mlrun/utils/helpers.py +66 -18
  228. mlrun/utils/logger.py +106 -4
  229. mlrun/utils/notifications/notification/__init__.py +22 -19
  230. mlrun/utils/notifications/notification/base.py +33 -14
  231. mlrun/utils/notifications/notification/console.py +6 -6
  232. mlrun/utils/notifications/notification/git.py +11 -11
  233. mlrun/utils/notifications/notification/ipython.py +10 -9
  234. mlrun/utils/notifications/notification/mail.py +176 -0
  235. mlrun/utils/notifications/notification/slack.py +6 -6
  236. mlrun/utils/notifications/notification/webhook.py +6 -6
  237. mlrun/utils/notifications/notification_pusher.py +86 -44
  238. mlrun/utils/regex.py +3 -1
  239. mlrun/utils/version/version.json +2 -2
  240. {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/METADATA +191 -186
  241. mlrun-1.8.0rc8.dist-info/RECORD +347 -0
  242. {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/WHEEL +1 -1
  243. mlrun/model_monitoring/db/stores/__init__.py +0 -136
  244. mlrun/model_monitoring/db/stores/base/store.py +0 -213
  245. mlrun/model_monitoring/db/stores/sqldb/__init__.py +0 -13
  246. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -71
  247. mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -190
  248. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +0 -103
  249. mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -40
  250. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +0 -659
  251. mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +0 -13
  252. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +0 -726
  253. mlrun/model_monitoring/model_endpoint.py +0 -118
  254. mlrun-1.7.1rc4.dist-info/RECORD +0 -351
  255. {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/LICENSE +0 -0
  256. {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/entry_points.txt +0 -0
  257. {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/top_level.txt +0 -0
mlrun/model.py CHANGED
@@ -24,7 +24,7 @@ from datetime import datetime
24
24
  from os import environ
25
25
  from typing import Any, Optional, Union
26
26
 
27
- import pydantic.error_wrappers
27
+ import pydantic.v1.error_wrappers
28
28
 
29
29
  import mlrun
30
30
  import mlrun.common.constants as mlrun_constants
@@ -74,7 +74,10 @@ class ModelObj:
74
74
 
75
75
  @mlrun.utils.filter_warnings("ignore", FutureWarning)
76
76
  def to_dict(
77
- self, fields: list = None, exclude: list = None, strip: bool = False
77
+ self,
78
+ fields: Optional[list] = None,
79
+ exclude: Optional[list] = None,
80
+ strip: bool = False,
78
81
  ) -> dict:
79
82
  """
80
83
  Convert the object to a dict
@@ -114,6 +117,8 @@ class ModelObj:
114
117
  # If one of the attributes is a third party object that has to_dict method (such as k8s objects), then
115
118
  # add it to the object's _fields_to_serialize attribute and handle it in the _serialize_field method.
116
119
  if hasattr(field_value, "to_dict"):
120
+ # TODO: Allow passing fields to exclude from the parent object to the child object
121
+ # e.g.: run.to_dict(exclude=["status.artifacts"])
117
122
  field_value = field_value.to_dict(strip=strip)
118
123
  if self._is_valid_field_value_for_serialization(
119
124
  field_name, field_value, strip
@@ -141,7 +146,7 @@ class ModelObj:
141
146
  self._apply_enrichment_before_to_dict_completion(struct, strip=strip)
142
147
  return struct
143
148
 
144
- def _resolve_initial_to_dict_fields(self, fields: list = None) -> list:
149
+ def _resolve_initial_to_dict_fields(self, fields: Optional[list] = None) -> list:
145
150
  """
146
151
  Resolve fields to be used in to_dict method.
147
152
  If fields is None, use `_dict_fields` attribute of the object.
@@ -184,7 +189,7 @@ class ModelObj:
184
189
  self,
185
190
  struct: dict,
186
191
  method: typing.Callable,
187
- fields: typing.Union[list, set] = None,
192
+ fields: Optional[typing.Union[list, set]] = None,
188
193
  strip: bool = False,
189
194
  ) -> dict:
190
195
  for field_name in fields:
@@ -196,14 +201,14 @@ class ModelObj:
196
201
  return struct
197
202
 
198
203
  def _serialize_field(
199
- self, struct: dict, field_name: str = None, strip: bool = False
204
+ self, struct: dict, field_name: Optional[str] = None, strip: bool = False
200
205
  ) -> typing.Any:
201
206
  # We pull the field from self and not from struct because it was excluded from the struct when looping over
202
207
  # the fields to save.
203
208
  return getattr(self, field_name, None)
204
209
 
205
210
  def _enrich_field(
206
- self, struct: dict, field_name: str = None, strip: bool = False
211
+ self, struct: dict, field_name: Optional[str] = None, strip: bool = False
207
212
  ) -> typing.Any:
208
213
  # We first try to pull from struct because the field might have been already serialized and if not,
209
214
  # we pull from self
@@ -215,7 +220,9 @@ class ModelObj:
215
220
  return struct
216
221
 
217
222
  @classmethod
218
- def from_dict(cls, struct=None, fields=None, deprecated_fields: dict = None):
223
+ def from_dict(
224
+ cls, struct=None, fields=None, deprecated_fields: Optional[dict] = None
225
+ ):
219
226
  """create an object from a python dictionary"""
220
227
  struct = {} if struct is None else struct
221
228
  deprecated_fields = deprecated_fields or {}
@@ -430,7 +437,7 @@ class Credentials(ModelObj):
430
437
 
431
438
  def __init__(
432
439
  self,
433
- access_key: str = None,
440
+ access_key: Optional[str] = None,
434
441
  ):
435
442
  self.access_key = access_key
436
443
 
@@ -438,6 +445,7 @@ class Credentials(ModelObj):
438
445
  class BaseMetadata(ModelObj):
439
446
  _default_fields_to_strip = ModelObj._default_fields_to_strip + [
440
447
  "hash",
448
+ "uid",
441
449
  # Below are environment specific fields, no need to keep when stripping
442
450
  "namespace",
443
451
  "project",
@@ -460,10 +468,12 @@ class BaseMetadata(ModelObj):
460
468
  categories=None,
461
469
  updated=None,
462
470
  credentials=None,
471
+ uid=None,
463
472
  ):
464
473
  self.name = name
465
474
  self.tag = tag
466
475
  self.hash = hash
476
+ self.uid = uid
467
477
  self.namespace = namespace
468
478
  self.project = project or ""
469
479
  self.labels = labels or {}
@@ -500,7 +510,7 @@ class ImageBuilder(ModelObj):
500
510
  origin_filename=None,
501
511
  with_mlrun=None,
502
512
  auto_build=None,
503
- requirements: list = None,
513
+ requirements: Optional[list] = None,
504
514
  extra_args=None,
505
515
  builder_env=None,
506
516
  source_code_target_dir=None,
@@ -549,7 +559,7 @@ class ImageBuilder(ModelObj):
549
559
  self,
550
560
  image="",
551
561
  base_image=None,
552
- commands: list = None,
562
+ commands: Optional[list] = None,
553
563
  secret=None,
554
564
  source=None,
555
565
  extra=None,
@@ -734,7 +744,7 @@ class Notification(ModelObj):
734
744
  def validate_notification(self):
735
745
  try:
736
746
  mlrun.common.schemas.notification.Notification(**self.to_dict())
737
- except pydantic.error_wrappers.ValidationError as exc:
747
+ except pydantic.v1.error_wrappers.ValidationError as exc:
738
748
  raise mlrun.errors.MLRunInvalidArgumentError(
739
749
  "Invalid notification object"
740
750
  ) from exc
@@ -750,14 +760,14 @@ class Notification(ModelObj):
750
760
  "Notification params size exceeds max size of 1 MB"
751
761
  )
752
762
 
753
- def validate_notification_params(self):
754
- notification_class = mlrun.utils.notifications.NotificationTypes(
755
- self.kind
756
- ).get_notification()
757
-
763
+ def validate_notification_params(self, default_notification_params=None):
764
+ default_notification_params = default_notification_params or {}
765
+ notification_type = mlrun.utils.notifications.NotificationTypes(self.kind)
766
+ notification_class = notification_type.get_notification()
758
767
  secret_params = self.secret_params or {}
759
768
  params = self.params or {}
760
-
769
+ default_params = default_notification_params.get(notification_type, {})
770
+ params = notification_class.enrich_default_params(params, default_params)
761
771
  # if the secret_params are already masked - no need to validate
762
772
  params_secret = secret_params.get("secret", "")
763
773
  if params_secret:
@@ -973,7 +983,7 @@ class RunSpec(ModelObj):
973
983
  self.node_selector = node_selector or {}
974
984
 
975
985
  def _serialize_field(
976
- self, struct: dict, field_name: str = None, strip: bool = False
986
+ self, struct: dict, field_name: Optional[str] = None, strip: bool = False
977
987
  ) -> Optional[str]:
978
988
  # We pull the field from self and not from struct because it was excluded from the struct
979
989
  if field_name == "handler":
@@ -1262,6 +1272,8 @@ class RunSpec(ModelObj):
1262
1272
  class RunStatus(ModelObj):
1263
1273
  """Run status"""
1264
1274
 
1275
+ _default_fields_to_strip = ModelObj._default_fields_to_strip + ["artifacts"]
1276
+
1265
1277
  def __init__(
1266
1278
  self,
1267
1279
  state=None,
@@ -1275,9 +1287,9 @@ class RunStatus(ModelObj):
1275
1287
  last_update=None,
1276
1288
  iterations=None,
1277
1289
  ui_url=None,
1278
- reason: str = None,
1279
- notifications: dict[str, Notification] = None,
1280
- artifact_uris: dict[str, str] = None,
1290
+ reason: Optional[str] = None,
1291
+ notifications: Optional[dict[str, Notification]] = None,
1292
+ artifact_uris: Optional[dict[str, str]] = None,
1281
1293
  ):
1282
1294
  self.state = state or "created"
1283
1295
  self.status_text = status_text
@@ -1285,7 +1297,7 @@ class RunStatus(ModelObj):
1285
1297
  self.host = host
1286
1298
  self.commit = commit
1287
1299
  self.results = results
1288
- self.artifacts = artifacts
1300
+ self._artifacts = artifacts
1289
1301
  self.start_time = start_time
1290
1302
  self.last_update = last_update
1291
1303
  self.iterations = iterations
@@ -1293,7 +1305,59 @@ class RunStatus(ModelObj):
1293
1305
  self.reason = reason
1294
1306
  self.notifications = notifications or {}
1295
1307
  # Artifact key -> URI mapping, since the full artifacts are not stored in the runs DB table
1296
- self.artifact_uris = artifact_uris or {}
1308
+ self._artifact_uris = artifact_uris or {}
1309
+
1310
+ @classmethod
1311
+ def from_dict(
1312
+ cls, struct=None, fields=None, deprecated_fields: Optional[dict] = None
1313
+ ):
1314
+ deprecated_fields = {
1315
+ # Set artifacts as deprecated for lazy loading
1316
+ "artifacts": "artifact_uris"
1317
+ }
1318
+ return super().from_dict(
1319
+ struct, fields=fields, deprecated_fields=deprecated_fields
1320
+ )
1321
+
1322
+ @property
1323
+ def artifacts(self):
1324
+ """
1325
+ Artifacts are lazy loaded to reduce memory consumption.
1326
+ We keep artifact_uris (key -> store URI dictionary) to be able to get the run artifacts easily.
1327
+ If the artifact is not already in the cache, we get it from the store (DB).
1328
+ :return: List of artifact dictionaries
1329
+ """
1330
+ self._artifacts = self._artifacts or []
1331
+ existing_artifact_keys = {
1332
+ artifact["metadata"]["key"] for artifact in self._artifacts
1333
+ }
1334
+ for key, uri in self.artifact_uris.items():
1335
+ if key not in existing_artifact_keys:
1336
+ artifact = mlrun.datastore.get_store_resource(uri)
1337
+ self._artifacts.append(artifact.to_dict())
1338
+ return self._artifacts
1339
+
1340
+ @artifacts.setter
1341
+ def artifacts(self, artifacts):
1342
+ self._artifacts = artifacts
1343
+
1344
+ @property
1345
+ def artifact_uris(self):
1346
+ return self._artifact_uris
1347
+
1348
+ @artifact_uris.setter
1349
+ def artifact_uris(self, artifact_uris):
1350
+ resolved_artifact_uris = {}
1351
+ if isinstance(artifact_uris, list):
1352
+ # artifact_uris is the deprecated list of artifacts - convert to new form
1353
+ for artifact in artifact_uris:
1354
+ if isinstance(artifact, dict):
1355
+ artifact = mlrun.artifacts.dict_to_artifact(artifact)
1356
+ resolved_artifact_uris[artifact.key] = artifact.uri
1357
+ else:
1358
+ resolved_artifact_uris = artifact_uris
1359
+
1360
+ self._artifact_uris = resolved_artifact_uris
1297
1361
 
1298
1362
  def is_failed(self) -> Optional[bool]:
1299
1363
  """
@@ -1601,7 +1665,7 @@ class RunObject(RunTemplate):
1601
1665
 
1602
1666
  return outputs
1603
1667
 
1604
- def artifact(self, key: str) -> "mlrun.DataItem":
1668
+ def artifact(self, key: str) -> typing.Optional["mlrun.DataItem"]:
1605
1669
  """Return artifact DataItem by key.
1606
1670
 
1607
1671
  This method waits for the outputs to complete, searches for the artifact matching the given key,
@@ -1644,7 +1708,7 @@ class RunObject(RunTemplate):
1644
1708
  :param key: The key of the artifact to retrieve.
1645
1709
  :return: The last artifact DataItem with the given key, or None if no such artifact is found.
1646
1710
  """
1647
- if not self.status.artifacts:
1711
+ if not self.status.artifacts and not self.status.artifact_uris:
1648
1712
  return None
1649
1713
 
1650
1714
  # Collect artifacts that match the key
@@ -1655,7 +1719,12 @@ class RunObject(RunTemplate):
1655
1719
  ]
1656
1720
 
1657
1721
  if not matching_artifacts:
1658
- return None
1722
+ if key not in self.status.artifact_uris:
1723
+ return None
1724
+
1725
+ # Get artifact by store URI sanity (should have been enriched by now in status.artifacts property)
1726
+ artifact_uri = self.status.artifact_uris[key]
1727
+ return mlrun.datastore.get_store_resource(artifact_uri)
1659
1728
 
1660
1729
  # Sort matching artifacts by creation date in ascending order.
1661
1730
  # The last element in the list will be the one created most recently.
@@ -1870,7 +1939,7 @@ class EntrypointParam(ModelObj):
1870
1939
  default=None,
1871
1940
  doc="",
1872
1941
  required=None,
1873
- choices: list = None,
1942
+ choices: Optional[list] = None,
1874
1943
  ):
1875
1944
  self.name = name
1876
1945
  self.type = type
@@ -2065,12 +2134,12 @@ class DataSource(ModelObj):
2065
2134
 
2066
2135
  def __init__(
2067
2136
  self,
2068
- name: str = None,
2069
- path: str = None,
2070
- attributes: dict[str, object] = None,
2071
- key_field: str = None,
2072
- time_field: str = None,
2073
- schedule: str = None,
2137
+ name: Optional[str] = None,
2138
+ path: Optional[str] = None,
2139
+ attributes: Optional[dict[str, object]] = None,
2140
+ key_field: Optional[str] = None,
2141
+ time_field: Optional[str] = None,
2142
+ schedule: Optional[str] = None,
2074
2143
  start_time: Optional[Union[datetime, str]] = None,
2075
2144
  end_time: Optional[Union[datetime, str]] = None,
2076
2145
  ):
@@ -2092,7 +2161,7 @@ class DataSource(ModelObj):
2092
2161
  self._secrets = secrets
2093
2162
 
2094
2163
  def _serialize_field(
2095
- self, struct: dict, field_name: str = None, strip: bool = False
2164
+ self, struct: dict, field_name: Optional[str] = None, strip: bool = False
2096
2165
  ) -> typing.Any:
2097
2166
  value = super()._serialize_field(struct, field_name, strip)
2098
2167
  # We pull the field from self and not from struct because it was excluded from the struct when looping over
@@ -2124,7 +2193,9 @@ class DataTargetBase(ModelObj):
2124
2193
  ]
2125
2194
 
2126
2195
  @classmethod
2127
- def from_dict(cls, struct=None, fields=None, deprecated_fields: dict = None):
2196
+ def from_dict(
2197
+ cls, struct=None, fields=None, deprecated_fields: Optional[dict] = None
2198
+ ):
2128
2199
  return super().from_dict(struct, fields=fields)
2129
2200
 
2130
2201
  def get_path(self):
@@ -2140,10 +2211,10 @@ class DataTargetBase(ModelObj):
2140
2211
 
2141
2212
  def __init__(
2142
2213
  self,
2143
- kind: str = None,
2214
+ kind: Optional[str] = None,
2144
2215
  name: str = "",
2145
2216
  path=None,
2146
- attributes: dict[str, str] = None,
2217
+ attributes: Optional[dict[str, str]] = None,
2147
2218
  after_step=None,
2148
2219
  partitioned: bool = False,
2149
2220
  key_bucketing_number: Optional[int] = None,
@@ -2151,8 +2222,8 @@ class DataTargetBase(ModelObj):
2151
2222
  time_partitioning_granularity: Optional[str] = None,
2152
2223
  max_events: Optional[int] = None,
2153
2224
  flush_after_seconds: Optional[int] = None,
2154
- storage_options: dict[str, str] = None,
2155
- schema: dict[str, Any] = None,
2225
+ storage_options: Optional[dict[str, str]] = None,
2226
+ schema: Optional[dict[str, Any]] = None,
2156
2227
  credentials_prefix=None,
2157
2228
  ):
2158
2229
  self.name = name
@@ -2208,7 +2279,7 @@ class DataTarget(DataTargetBase):
2208
2279
 
2209
2280
  def __init__(
2210
2281
  self,
2211
- kind: str = None,
2282
+ kind: Optional[str] = None,
2212
2283
  name: str = "",
2213
2284
  path=None,
2214
2285
  online=None,
@@ -2237,12 +2308,12 @@ class DataTarget(DataTargetBase):
2237
2308
  class VersionedObjMetadata(ModelObj):
2238
2309
  def __init__(
2239
2310
  self,
2240
- name: str = None,
2241
- tag: str = None,
2242
- uid: str = None,
2243
- project: str = None,
2244
- labels: dict[str, str] = None,
2245
- annotations: dict[str, str] = None,
2311
+ name: Optional[str] = None,
2312
+ tag: Optional[str] = None,
2313
+ uid: Optional[str] = None,
2314
+ project: Optional[str] = None,
2315
+ labels: Optional[dict[str, str]] = None,
2316
+ annotations: Optional[dict[str, str]] = None,
2246
2317
  updated=None,
2247
2318
  ):
2248
2319
  self.name = name
@@ -11,11 +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
- # flake8: noqa - this is until we take care of the F401 violations with respect to __all__ & sphinx
14
+
16
15
  # for backwards compatibility
17
16
 
18
- from .db import get_store_object, get_tsdb_connector
17
+ from mlrun.common.schemas import ModelEndpoint, ModelEndpointList
18
+
19
+ from .db import get_tsdb_connector
19
20
  from .helpers import get_stream_path
20
- from .model_endpoint import ModelEndpoint
21
21
  from .tracking_policy import TrackingPolicy
@@ -23,18 +23,28 @@ import pandas as pd
23
23
  import mlrun.artifacts
24
24
  import mlrun.common.helpers
25
25
  import mlrun.common.schemas.model_monitoring.constants as mm_constants
26
+ import mlrun.datastore.base
26
27
  import mlrun.feature_store
27
28
  import mlrun.model_monitoring.applications as mm_app
28
29
  import mlrun.serving
30
+ from mlrun.common.schemas import ModelEndpoint
31
+ from mlrun.common.schemas.model_monitoring import (
32
+ FunctionURI,
33
+ )
29
34
  from mlrun.data_types.infer import InferOptions, get_df_stats
30
35
  from mlrun.utils import datetime_now, logger
31
36
 
32
37
  from .helpers import update_model_endpoint_last_request
33
- from .model_endpoint import ModelEndpoint
34
38
 
35
39
  # A union of all supported dataset types:
36
40
  DatasetType = typing.Union[
37
- mlrun.DataItem, list, dict, pd.DataFrame, pd.Series, np.ndarray, typing.Any
41
+ mlrun.datastore.base.DataItem,
42
+ list,
43
+ dict,
44
+ pd.DataFrame,
45
+ pd.Series,
46
+ np.ndarray,
47
+ typing.Any,
38
48
  ]
39
49
 
40
50
 
@@ -44,10 +54,8 @@ def get_or_create_model_endpoint(
44
54
  model_endpoint_name: str = "",
45
55
  endpoint_id: str = "",
46
56
  function_name: str = "",
47
- context: mlrun.MLClientCtx = None,
48
- sample_set_statistics: dict[str, typing.Any] = None,
49
- drift_threshold: typing.Optional[float] = None,
50
- possible_drift_threshold: typing.Optional[float] = None,
57
+ context: typing.Optional["mlrun.MLClientCtx"] = None,
58
+ sample_set_statistics: typing.Optional[dict[str, typing.Any]] = None,
51
59
  monitoring_mode: mm_constants.ModelMonitoringMode = mm_constants.ModelMonitoringMode.disabled,
52
60
  db_session=None,
53
61
  ) -> ModelEndpoint:
@@ -68,10 +76,6 @@ def get_or_create_model_endpoint(
68
76
  full function hash.
69
77
  :param sample_set_statistics: Dictionary of sample set statistics that will be used as a reference data for
70
78
  the new model endpoint (applicable only to new endpoint_id).
71
- :param drift_threshold: (deprecated) The threshold of which to mark drifts (applicable only to new
72
- endpoint_id).
73
- :param possible_drift_threshold: (deprecated) The threshold of which to mark possible drifts (applicable only to new
74
- endpoint_id).
75
79
  :param monitoring_mode: If enabled, apply model monitoring features on the provided endpoint id
76
80
  (applicable only to new endpoint_id).
77
81
  :param db_session: A runtime session that manages the current dialog with the database.
@@ -79,18 +83,15 @@ def get_or_create_model_endpoint(
79
83
  :return: A ModelEndpoint object
80
84
  """
81
85
 
82
- if not endpoint_id:
83
- # Generate a new model endpoint id based on the project name and model name
84
- endpoint_id = hashlib.sha1(
85
- f"{project}_{model_endpoint_name}".encode()
86
- ).hexdigest()
87
-
88
86
  if not db_session:
89
87
  # Generate a runtime database
90
88
  db_session = mlrun.get_run_db()
91
89
  try:
92
90
  model_endpoint = db_session.get_model_endpoint(
93
- project=project, endpoint_id=endpoint_id
91
+ project=project,
92
+ name=model_endpoint_name,
93
+ endpoint_id=endpoint_id,
94
+ function_name=function_name,
94
95
  )
95
96
  # If other fields provided, validate that they are correspond to the existing model endpoint data
96
97
  _model_endpoint_validations(
@@ -104,7 +105,6 @@ def get_or_create_model_endpoint(
104
105
  model_endpoint = _generate_model_endpoint(
105
106
  project=project,
106
107
  db_session=db_session,
107
- endpoint_id=endpoint_id,
108
108
  model_path=model_path,
109
109
  model_endpoint_name=model_endpoint_name,
110
110
  function_name=function_name,
@@ -121,7 +121,7 @@ def record_results(
121
121
  model_endpoint_name: str,
122
122
  endpoint_id: str = "",
123
123
  function_name: str = "",
124
- context: typing.Optional[mlrun.MLClientCtx] = None,
124
+ context: typing.Optional["mlrun.MLClientCtx"] = None,
125
125
  infer_results_df: typing.Optional[pd.DataFrame] = None,
126
126
  sample_set_statistics: typing.Optional[dict[str, typing.Any]] = None,
127
127
  monitoring_mode: mm_constants.ModelMonitoringMode = mm_constants.ModelMonitoringMode.enabled,
@@ -208,13 +208,13 @@ def record_results(
208
208
  monitoring_mode=monitoring_mode,
209
209
  db_session=db,
210
210
  )
211
- logger.debug("Model endpoint", endpoint=model_endpoint.to_dict())
211
+ logger.debug("Model endpoint", endpoint=model_endpoint)
212
212
 
213
213
  timestamp = datetime_now()
214
214
  if infer_results_df is not None:
215
215
  # Write the monitoring parquet to the relevant model endpoint context
216
216
  write_monitoring_df(
217
- feature_set_uri=model_endpoint.status.monitoring_feature_set_uri,
217
+ feature_set_uri=model_endpoint.spec.monitoring_feature_set_uri,
218
218
  infer_datetime=timestamp,
219
219
  endpoint_id=model_endpoint.metadata.uid,
220
220
  infer_results_df=infer_results_df,
@@ -234,7 +234,7 @@ def record_results(
234
234
  def _model_endpoint_validations(
235
235
  model_endpoint: ModelEndpoint,
236
236
  model_path: str = "",
237
- sample_set_statistics: dict[str, typing.Any] = None,
237
+ sample_set_statistics: typing.Optional[dict[str, typing.Any]] = None,
238
238
  ) -> None:
239
239
  """
240
240
  Validate that provided model endpoint configurations match the stored fields of the provided `ModelEndpoint`
@@ -278,7 +278,7 @@ def _model_endpoint_validations(
278
278
  # Feature stats
279
279
  if (
280
280
  sample_set_statistics
281
- and sample_set_statistics != model_endpoint.status.feature_stats
281
+ and sample_set_statistics != model_endpoint.spec.feature_stats
282
282
  ):
283
283
  logger.warning(
284
284
  "Provided sample set statistics is different from the registered statistics. "
@@ -290,7 +290,7 @@ def write_monitoring_df(
290
290
  endpoint_id: str,
291
291
  infer_results_df: pd.DataFrame,
292
292
  infer_datetime: datetime,
293
- monitoring_feature_set: typing.Optional[mlrun.feature_store.FeatureSet] = None,
293
+ monitoring_feature_set: typing.Optional["mlrun.feature_store.FeatureSet"] = None,
294
294
  feature_set_uri: str = "",
295
295
  ) -> None:
296
296
  """Write infer results dataframe to the monitoring parquet target of the current model endpoint. The dataframe will
@@ -330,11 +330,10 @@ def write_monitoring_df(
330
330
  def _generate_model_endpoint(
331
331
  project: str,
332
332
  db_session,
333
- endpoint_id: str,
334
333
  model_path: str,
335
334
  model_endpoint_name: str,
336
335
  function_name: str,
337
- context: mlrun.MLClientCtx,
336
+ context: "mlrun.MLClientCtx",
338
337
  sample_set_statistics: dict[str, typing.Any],
339
338
  monitoring_mode: mm_constants.ModelMonitoringMode = mm_constants.ModelMonitoringMode.disabled,
340
339
  ) -> ModelEndpoint:
@@ -344,7 +343,6 @@ def _generate_model_endpoint(
344
343
  :param project: Project name.
345
344
 
346
345
  :param db_session: A session that manages the current dialog with the database.
347
- :param endpoint_id: Model endpoint unique ID.
348
346
  :param model_path: The model Store path.
349
347
  :param model_endpoint_name: Model endpoint name will be presented under the new model endpoint.
350
348
  :param function_name: If a new model endpoint is created, use this function name for generating the
@@ -355,39 +353,45 @@ def _generate_model_endpoint(
355
353
  the current model endpoint. Will be stored under
356
354
  `model_endpoint.status.feature_stats`.
357
355
 
358
- :return `mlrun.model_monitoring.model_endpoint.ModelEndpoint` object.
356
+ :return `mlrun.common.schemas.ModelEndpoint` object.
359
357
  """
360
- model_endpoint = ModelEndpoint()
361
- model_endpoint.metadata.project = project
362
- model_endpoint.metadata.uid = endpoint_id
363
- if function_name:
364
- model_endpoint.spec.function_uri = project + "/" + function_name
365
- elif not context:
366
- raise mlrun.errors.MLRunInvalidArgumentError(
367
- "Please provide either a function name or a valid MLRun context"
358
+ if not function_name and context:
359
+ function_name = FunctionURI.from_string(
360
+ context.to_dict()["spec"]["function"]
361
+ ).function
362
+ model_obj = None
363
+ if model_path:
364
+ model_obj: mlrun.artifacts.ModelArtifact = (
365
+ mlrun.datastore.store_resources.get_store_resource(
366
+ model_path, db=db_session
367
+ )
368
368
  )
369
- else:
370
- model_endpoint.spec.function_uri = context.to_dict()["spec"]["function"]
371
- model_endpoint.spec.model_uri = model_path
372
- model_endpoint.spec.model = model_endpoint_name
373
- model_endpoint.spec.model_class = "drift-analysis"
374
- model_endpoint.spec.monitoring_mode = monitoring_mode
375
- model_endpoint.status.first_request = model_endpoint.status.last_request = (
376
- datetime_now().isoformat()
377
- )
378
- if sample_set_statistics:
379
- model_endpoint.status.feature_stats = sample_set_statistics
380
-
381
- db_session.create_model_endpoint(
382
- project=project, endpoint_id=endpoint_id, model_endpoint=model_endpoint
369
+ current_time = datetime_now()
370
+ model_endpoint = mlrun.common.schemas.ModelEndpoint(
371
+ metadata=mlrun.common.schemas.ModelEndpointMetadata(
372
+ project=project,
373
+ name=model_endpoint_name,
374
+ endpoint_type=mlrun.common.schemas.model_monitoring.EndpointType.BATCH_EP,
375
+ ),
376
+ spec=mlrun.common.schemas.ModelEndpointSpec(
377
+ function_name=function_name,
378
+ model_name=model_obj.metadata.key if model_path else None,
379
+ model_uid=model_obj.metadata.uid if model_path else None,
380
+ model_class="drift-analysis",
381
+ ),
382
+ status=mlrun.common.schemas.ModelEndpointStatus(
383
+ monitoring_mode=monitoring_mode,
384
+ first_request=current_time,
385
+ last_request=current_time,
386
+ ),
383
387
  )
384
388
 
385
- return db_session.get_model_endpoint(project=project, endpoint_id=endpoint_id)
389
+ return db_session.create_model_endpoint(model_endpoint=model_endpoint)
386
390
 
387
391
 
388
392
  def get_sample_set_statistics(
389
393
  sample_set: DatasetType = None,
390
- model_artifact_feature_stats: dict = None,
394
+ model_artifact_feature_stats: typing.Optional[dict] = None,
391
395
  sample_set_columns: typing.Optional[list] = None,
392
396
  sample_set_drop_columns: typing.Optional[list] = None,
393
397
  sample_set_label_columns: typing.Optional[list] = None,
@@ -445,9 +449,9 @@ def get_sample_set_statistics(
445
449
 
446
450
  def read_dataset_as_dataframe(
447
451
  dataset: DatasetType,
448
- feature_columns: typing.Union[str, list[str]] = None,
449
- label_columns: typing.Union[str, list[str]] = None,
450
- drop_columns: typing.Union[str, list[str], int, list[int]] = None,
452
+ feature_columns: typing.Optional[typing.Union[str, list[str]]] = None,
453
+ label_columns: typing.Optional[typing.Union[str, list[str]]] = None,
454
+ drop_columns: typing.Optional[typing.Union[str, list[str], int, list[int]]] = None,
451
455
  ) -> tuple[pd.DataFrame, list[str]]:
452
456
  """
453
457
  Parse the given dataset into a DataFrame and drop the columns accordingly. In addition, the label columns will be
@@ -531,7 +535,7 @@ def read_dataset_as_dataframe(
531
535
 
532
536
 
533
537
  def log_result(
534
- context: mlrun.MLClientCtx,
538
+ context: "mlrun.MLClientCtx",
535
539
  result_set_name: str,
536
540
  result_set: pd.DataFrame,
537
541
  artifacts_tag: str,
@@ -559,9 +563,7 @@ def _create_model_monitoring_function_base(
559
563
  project: str,
560
564
  func: typing.Union[str, None] = None,
561
565
  application_class: typing.Union[
562
- str,
563
- mm_app.ModelMonitoringApplicationBase,
564
- None,
566
+ str, "mm_app.ModelMonitoringApplicationBase", None
565
567
  ] = None,
566
568
  name: typing.Optional[str] = None,
567
569
  image: typing.Optional[str] = None,