mlrun 1.6.4rc2__py3-none-any.whl → 1.7.0rc20__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 (291) hide show
  1. mlrun/__init__.py +11 -1
  2. mlrun/__main__.py +26 -112
  3. mlrun/alerts/__init__.py +15 -0
  4. mlrun/alerts/alert.py +144 -0
  5. mlrun/api/schemas/__init__.py +5 -4
  6. mlrun/artifacts/__init__.py +8 -3
  7. mlrun/artifacts/base.py +46 -257
  8. mlrun/artifacts/dataset.py +11 -192
  9. mlrun/artifacts/manager.py +47 -48
  10. mlrun/artifacts/model.py +31 -159
  11. mlrun/artifacts/plots.py +23 -380
  12. mlrun/common/constants.py +69 -0
  13. mlrun/common/db/sql_session.py +2 -3
  14. mlrun/common/formatters/__init__.py +19 -0
  15. mlrun/common/formatters/artifact.py +21 -0
  16. mlrun/common/formatters/base.py +78 -0
  17. mlrun/common/formatters/function.py +41 -0
  18. mlrun/common/formatters/pipeline.py +53 -0
  19. mlrun/common/formatters/project.py +51 -0
  20. mlrun/common/helpers.py +1 -2
  21. mlrun/common/model_monitoring/helpers.py +9 -5
  22. mlrun/{runtimes → common/runtimes}/constants.py +37 -9
  23. mlrun/common/schemas/__init__.py +24 -4
  24. mlrun/common/schemas/alert.py +203 -0
  25. mlrun/common/schemas/api_gateway.py +148 -0
  26. mlrun/common/schemas/artifact.py +18 -8
  27. mlrun/common/schemas/auth.py +11 -5
  28. mlrun/common/schemas/background_task.py +1 -1
  29. mlrun/common/schemas/client_spec.py +4 -1
  30. mlrun/common/schemas/feature_store.py +16 -16
  31. mlrun/common/schemas/frontend_spec.py +8 -7
  32. mlrun/common/schemas/function.py +5 -1
  33. mlrun/common/schemas/hub.py +11 -18
  34. mlrun/common/schemas/memory_reports.py +2 -2
  35. mlrun/common/schemas/model_monitoring/__init__.py +18 -3
  36. mlrun/common/schemas/model_monitoring/constants.py +83 -26
  37. mlrun/common/schemas/model_monitoring/grafana.py +13 -9
  38. mlrun/common/schemas/model_monitoring/model_endpoints.py +99 -16
  39. mlrun/common/schemas/notification.py +4 -4
  40. mlrun/common/schemas/object.py +2 -2
  41. mlrun/{runtimes/mpijob/v1alpha1.py → common/schemas/pagination.py} +10 -13
  42. mlrun/common/schemas/pipeline.py +1 -10
  43. mlrun/common/schemas/project.py +24 -23
  44. mlrun/common/schemas/runtime_resource.py +8 -12
  45. mlrun/common/schemas/schedule.py +3 -3
  46. mlrun/common/schemas/tag.py +1 -2
  47. mlrun/common/schemas/workflow.py +2 -2
  48. mlrun/common/types.py +7 -1
  49. mlrun/config.py +54 -17
  50. mlrun/data_types/to_pandas.py +10 -12
  51. mlrun/datastore/__init__.py +5 -8
  52. mlrun/datastore/alibaba_oss.py +130 -0
  53. mlrun/datastore/azure_blob.py +17 -5
  54. mlrun/datastore/base.py +62 -39
  55. mlrun/datastore/datastore.py +28 -9
  56. mlrun/datastore/datastore_profile.py +146 -20
  57. mlrun/datastore/filestore.py +0 -1
  58. mlrun/datastore/google_cloud_storage.py +6 -2
  59. mlrun/datastore/hdfs.py +56 -0
  60. mlrun/datastore/inmem.py +2 -2
  61. mlrun/datastore/redis.py +6 -2
  62. mlrun/datastore/s3.py +9 -0
  63. mlrun/datastore/snowflake_utils.py +43 -0
  64. mlrun/datastore/sources.py +201 -96
  65. mlrun/datastore/spark_utils.py +1 -2
  66. mlrun/datastore/store_resources.py +7 -7
  67. mlrun/datastore/targets.py +358 -104
  68. mlrun/datastore/utils.py +72 -58
  69. mlrun/datastore/v3io.py +5 -1
  70. mlrun/db/base.py +185 -35
  71. mlrun/db/factory.py +1 -1
  72. mlrun/db/httpdb.py +614 -179
  73. mlrun/db/nopdb.py +210 -26
  74. mlrun/errors.py +12 -1
  75. mlrun/execution.py +41 -24
  76. mlrun/feature_store/__init__.py +0 -2
  77. mlrun/feature_store/api.py +40 -72
  78. mlrun/feature_store/common.py +1 -1
  79. mlrun/feature_store/feature_set.py +76 -55
  80. mlrun/feature_store/feature_vector.py +28 -30
  81. mlrun/feature_store/ingestion.py +7 -6
  82. mlrun/feature_store/retrieval/base.py +16 -11
  83. mlrun/feature_store/retrieval/conversion.py +11 -13
  84. mlrun/feature_store/retrieval/dask_merger.py +2 -0
  85. mlrun/feature_store/retrieval/job.py +9 -3
  86. mlrun/feature_store/retrieval/local_merger.py +2 -0
  87. mlrun/feature_store/retrieval/spark_merger.py +34 -24
  88. mlrun/feature_store/steps.py +37 -34
  89. mlrun/features.py +9 -20
  90. mlrun/frameworks/_common/artifacts_library.py +9 -9
  91. mlrun/frameworks/_common/mlrun_interface.py +5 -5
  92. mlrun/frameworks/_common/model_handler.py +48 -48
  93. mlrun/frameworks/_common/plan.py +2 -3
  94. mlrun/frameworks/_common/producer.py +3 -4
  95. mlrun/frameworks/_common/utils.py +5 -5
  96. mlrun/frameworks/_dl_common/loggers/logger.py +6 -7
  97. mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +9 -9
  98. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +23 -47
  99. mlrun/frameworks/_ml_common/artifacts_library.py +1 -2
  100. mlrun/frameworks/_ml_common/loggers/logger.py +3 -4
  101. mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +4 -5
  102. mlrun/frameworks/_ml_common/model_handler.py +24 -24
  103. mlrun/frameworks/_ml_common/pkl_model_server.py +2 -2
  104. mlrun/frameworks/_ml_common/plan.py +1 -1
  105. mlrun/frameworks/_ml_common/plans/calibration_curve_plan.py +2 -3
  106. mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +2 -3
  107. mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
  108. mlrun/frameworks/_ml_common/plans/feature_importance_plan.py +3 -3
  109. mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
  110. mlrun/frameworks/_ml_common/utils.py +4 -4
  111. mlrun/frameworks/auto_mlrun/auto_mlrun.py +9 -9
  112. mlrun/frameworks/huggingface/model_server.py +4 -4
  113. mlrun/frameworks/lgbm/__init__.py +33 -33
  114. mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
  115. mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -5
  116. mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -5
  117. mlrun/frameworks/lgbm/mlrun_interfaces/booster_mlrun_interface.py +1 -3
  118. mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +6 -6
  119. mlrun/frameworks/lgbm/model_handler.py +10 -10
  120. mlrun/frameworks/lgbm/model_server.py +6 -6
  121. mlrun/frameworks/lgbm/utils.py +5 -5
  122. mlrun/frameworks/onnx/dataset.py +8 -8
  123. mlrun/frameworks/onnx/mlrun_interface.py +3 -3
  124. mlrun/frameworks/onnx/model_handler.py +6 -6
  125. mlrun/frameworks/onnx/model_server.py +7 -7
  126. mlrun/frameworks/parallel_coordinates.py +4 -3
  127. mlrun/frameworks/pytorch/__init__.py +18 -18
  128. mlrun/frameworks/pytorch/callbacks/callback.py +4 -5
  129. mlrun/frameworks/pytorch/callbacks/logging_callback.py +17 -17
  130. mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +11 -11
  131. mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +23 -29
  132. mlrun/frameworks/pytorch/callbacks_handler.py +38 -38
  133. mlrun/frameworks/pytorch/mlrun_interface.py +20 -20
  134. mlrun/frameworks/pytorch/model_handler.py +17 -17
  135. mlrun/frameworks/pytorch/model_server.py +7 -7
  136. mlrun/frameworks/sklearn/__init__.py +13 -13
  137. mlrun/frameworks/sklearn/estimator.py +4 -4
  138. mlrun/frameworks/sklearn/metrics_library.py +14 -14
  139. mlrun/frameworks/sklearn/mlrun_interface.py +3 -6
  140. mlrun/frameworks/sklearn/model_handler.py +2 -2
  141. mlrun/frameworks/tf_keras/__init__.py +10 -7
  142. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +15 -15
  143. mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +11 -11
  144. mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +19 -23
  145. mlrun/frameworks/tf_keras/mlrun_interface.py +9 -11
  146. mlrun/frameworks/tf_keras/model_handler.py +14 -14
  147. mlrun/frameworks/tf_keras/model_server.py +6 -6
  148. mlrun/frameworks/xgboost/__init__.py +13 -13
  149. mlrun/frameworks/xgboost/model_handler.py +6 -6
  150. mlrun/k8s_utils.py +14 -16
  151. mlrun/launcher/__init__.py +1 -1
  152. mlrun/launcher/base.py +16 -15
  153. mlrun/launcher/client.py +8 -6
  154. mlrun/launcher/factory.py +1 -1
  155. mlrun/launcher/local.py +17 -11
  156. mlrun/launcher/remote.py +16 -10
  157. mlrun/lists.py +7 -6
  158. mlrun/model.py +238 -73
  159. mlrun/model_monitoring/__init__.py +1 -1
  160. mlrun/model_monitoring/api.py +138 -315
  161. mlrun/model_monitoring/application.py +5 -296
  162. mlrun/model_monitoring/applications/__init__.py +24 -0
  163. mlrun/model_monitoring/applications/_application_steps.py +157 -0
  164. mlrun/model_monitoring/applications/base.py +282 -0
  165. mlrun/model_monitoring/applications/context.py +214 -0
  166. mlrun/model_monitoring/applications/evidently_base.py +211 -0
  167. mlrun/model_monitoring/applications/histogram_data_drift.py +349 -0
  168. mlrun/model_monitoring/applications/results.py +99 -0
  169. mlrun/model_monitoring/controller.py +104 -84
  170. mlrun/model_monitoring/controller_handler.py +13 -5
  171. mlrun/model_monitoring/db/__init__.py +18 -0
  172. mlrun/model_monitoring/{stores → db/stores}/__init__.py +43 -36
  173. mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
  174. mlrun/model_monitoring/{stores/model_endpoint_store.py → db/stores/base/store.py} +64 -40
  175. mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
  176. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
  177. mlrun/model_monitoring/{stores → db/stores/sqldb}/models/base.py +109 -5
  178. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +88 -0
  179. mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
  180. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +684 -0
  181. mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
  182. mlrun/model_monitoring/{stores/kv_model_endpoint_store.py → db/stores/v3io_kv/kv_store.py} +310 -165
  183. mlrun/model_monitoring/db/tsdb/__init__.py +100 -0
  184. mlrun/model_monitoring/db/tsdb/base.py +329 -0
  185. mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
  186. mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
  187. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +240 -0
  188. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +45 -0
  189. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +397 -0
  190. mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
  191. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +117 -0
  192. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +630 -0
  193. mlrun/model_monitoring/evidently_application.py +6 -118
  194. mlrun/model_monitoring/features_drift_table.py +134 -106
  195. mlrun/model_monitoring/helpers.py +127 -28
  196. mlrun/model_monitoring/metrics/__init__.py +13 -0
  197. mlrun/model_monitoring/metrics/histogram_distance.py +127 -0
  198. mlrun/model_monitoring/model_endpoint.py +3 -2
  199. mlrun/model_monitoring/prometheus.py +1 -4
  200. mlrun/model_monitoring/stream_processing.py +62 -231
  201. mlrun/model_monitoring/tracking_policy.py +9 -2
  202. mlrun/model_monitoring/writer.py +152 -124
  203. mlrun/package/__init__.py +6 -6
  204. mlrun/package/context_handler.py +5 -5
  205. mlrun/package/packager.py +7 -7
  206. mlrun/package/packagers/default_packager.py +6 -6
  207. mlrun/package/packagers/numpy_packagers.py +15 -15
  208. mlrun/package/packagers/pandas_packagers.py +5 -5
  209. mlrun/package/packagers/python_standard_library_packagers.py +10 -10
  210. mlrun/package/packagers_manager.py +19 -23
  211. mlrun/package/utils/_formatter.py +6 -6
  212. mlrun/package/utils/_pickler.py +2 -2
  213. mlrun/package/utils/_supported_format.py +4 -4
  214. mlrun/package/utils/log_hint_utils.py +2 -2
  215. mlrun/package/utils/type_hint_utils.py +4 -9
  216. mlrun/platforms/__init__.py +11 -10
  217. mlrun/platforms/iguazio.py +24 -203
  218. mlrun/projects/operations.py +35 -21
  219. mlrun/projects/pipelines.py +68 -99
  220. mlrun/projects/project.py +830 -266
  221. mlrun/render.py +3 -11
  222. mlrun/run.py +162 -166
  223. mlrun/runtimes/__init__.py +62 -7
  224. mlrun/runtimes/base.py +39 -32
  225. mlrun/runtimes/daskjob.py +8 -8
  226. mlrun/runtimes/databricks_job/databricks_cancel_task.py +1 -1
  227. mlrun/runtimes/databricks_job/databricks_runtime.py +7 -7
  228. mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
  229. mlrun/runtimes/funcdoc.py +0 -28
  230. mlrun/runtimes/function_reference.py +1 -1
  231. mlrun/runtimes/kubejob.py +28 -122
  232. mlrun/runtimes/local.py +6 -3
  233. mlrun/runtimes/mpijob/__init__.py +0 -20
  234. mlrun/runtimes/mpijob/abstract.py +9 -10
  235. mlrun/runtimes/mpijob/v1.py +1 -1
  236. mlrun/{model_monitoring/stores/models/sqlite.py → runtimes/nuclio/__init__.py} +7 -9
  237. mlrun/runtimes/nuclio/api_gateway.py +709 -0
  238. mlrun/runtimes/nuclio/application/__init__.py +15 -0
  239. mlrun/runtimes/nuclio/application/application.py +523 -0
  240. mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
  241. mlrun/runtimes/{function.py → nuclio/function.py} +112 -73
  242. mlrun/runtimes/{nuclio.py → nuclio/nuclio.py} +6 -6
  243. mlrun/runtimes/{serving.py → nuclio/serving.py} +45 -51
  244. mlrun/runtimes/pod.py +286 -88
  245. mlrun/runtimes/remotesparkjob.py +2 -2
  246. mlrun/runtimes/sparkjob/spark3job.py +51 -34
  247. mlrun/runtimes/utils.py +7 -75
  248. mlrun/secrets.py +9 -5
  249. mlrun/serving/remote.py +2 -7
  250. mlrun/serving/routers.py +13 -10
  251. mlrun/serving/server.py +22 -26
  252. mlrun/serving/states.py +99 -25
  253. mlrun/serving/utils.py +3 -3
  254. mlrun/serving/v1_serving.py +6 -7
  255. mlrun/serving/v2_serving.py +59 -20
  256. mlrun/track/tracker.py +2 -1
  257. mlrun/track/tracker_manager.py +3 -3
  258. mlrun/track/trackers/mlflow_tracker.py +1 -2
  259. mlrun/utils/async_http.py +5 -7
  260. mlrun/utils/azure_vault.py +1 -1
  261. mlrun/utils/clones.py +1 -2
  262. mlrun/utils/condition_evaluator.py +3 -3
  263. mlrun/utils/db.py +3 -3
  264. mlrun/utils/helpers.py +183 -197
  265. mlrun/utils/http.py +2 -5
  266. mlrun/utils/logger.py +76 -14
  267. mlrun/utils/notifications/notification/__init__.py +17 -12
  268. mlrun/utils/notifications/notification/base.py +14 -2
  269. mlrun/utils/notifications/notification/console.py +2 -0
  270. mlrun/utils/notifications/notification/git.py +3 -1
  271. mlrun/utils/notifications/notification/ipython.py +3 -1
  272. mlrun/utils/notifications/notification/slack.py +101 -21
  273. mlrun/utils/notifications/notification/webhook.py +11 -1
  274. mlrun/utils/notifications/notification_pusher.py +155 -30
  275. mlrun/utils/retryer.py +208 -0
  276. mlrun/utils/singleton.py +1 -1
  277. mlrun/utils/v3io_clients.py +2 -4
  278. mlrun/utils/version/version.json +2 -2
  279. mlrun/utils/version/version.py +2 -6
  280. {mlrun-1.6.4rc2.dist-info → mlrun-1.7.0rc20.dist-info}/METADATA +31 -19
  281. mlrun-1.7.0rc20.dist-info/RECORD +353 -0
  282. mlrun/kfpops.py +0 -868
  283. mlrun/model_monitoring/batch.py +0 -1095
  284. mlrun/model_monitoring/stores/models/__init__.py +0 -27
  285. mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -384
  286. mlrun/platforms/other.py +0 -306
  287. mlrun-1.6.4rc2.dist-info/RECORD +0 -314
  288. {mlrun-1.6.4rc2.dist-info → mlrun-1.7.0rc20.dist-info}/LICENSE +0 -0
  289. {mlrun-1.6.4rc2.dist-info → mlrun-1.7.0rc20.dist-info}/WHEEL +0 -0
  290. {mlrun-1.6.4rc2.dist-info → mlrun-1.7.0rc20.dist-info}/entry_points.txt +0 -0
  291. {mlrun-1.6.4rc2.dist-info → mlrun-1.7.0rc20.dist-info}/top_level.txt +0 -0
mlrun/model.py CHANGED
@@ -22,18 +22,18 @@ from collections import OrderedDict
22
22
  from copy import deepcopy
23
23
  from datetime import datetime
24
24
  from os import environ
25
- from typing import Any, Dict, List, Optional, Tuple, Union
25
+ from typing import Any, Optional, Union
26
26
 
27
27
  import pydantic.error_wrappers
28
28
 
29
29
  import mlrun
30
+ import mlrun.common.constants as mlrun_constants
30
31
  import mlrun.common.schemas.notification
31
32
 
32
33
  from .utils import (
33
34
  dict_to_json,
34
35
  dict_to_yaml,
35
36
  get_artifact_target,
36
- is_legacy_artifact,
37
37
  logger,
38
38
  template_artifact_path,
39
39
  )
@@ -44,6 +44,15 @@ RUN_ID_PLACE_HOLDER = "{run_id}" # IMPORTANT: shouldn't be changed.
44
44
 
45
45
  class ModelObj:
46
46
  _dict_fields = []
47
+ # Bellow attributes are used in to_dict method
48
+ # Fields to strip from the object by default if strip=True
49
+ _default_fields_to_strip = []
50
+ # Fields that will be serialized by the object's _serialize_field method
51
+ _fields_to_serialize = []
52
+ # Fields that will be enriched by the object's _enrich_field method
53
+ _fields_to_enrich = []
54
+ # Fields that will be ignored by the object's _is_valid_field_value_for_serialization method
55
+ _fields_to_skip_validation = []
47
56
 
48
57
  @staticmethod
49
58
  def _verify_list(param, name):
@@ -63,26 +72,145 @@ class ModelObj:
63
72
  return param
64
73
 
65
74
  @mlrun.utils.filter_warnings("ignore", FutureWarning)
66
- def to_dict(self, fields=None, exclude=None):
67
- """convert the object to a python dictionary
75
+ def to_dict(
76
+ self, fields: list = None, exclude: list = None, strip: bool = False
77
+ ) -> dict:
78
+ """
79
+ Convert the object to a dict
80
+
81
+ :param fields: A list of fields to include in the dictionary. If not provided, the default value is taken
82
+ from `self._dict_fields` or from the object __init__ params.
83
+ :param exclude: A list of fields to exclude from the dictionary.
84
+ :param strip: If True, the object's `_default_fields_to_strip` attribute is appended to the exclude list.
85
+ Strip purpose is to remove fields that are context / environment specific and not required for actually
86
+ define the object.
68
87
 
69
- :param fields: list of fields to include in the dict
70
- :param exclude: list of fields to exclude from the dict
88
+ :return: A dictionary representation of the object.
71
89
  """
72
90
  struct = {}
73
- fields = fields or self._dict_fields
74
- if not fields:
75
- fields = list(inspect.signature(self.__init__).parameters.keys())
76
- for t in fields:
77
- if not exclude or t not in exclude:
78
- val = getattr(self, t, None)
79
- if val is not None and not (isinstance(val, dict) and not val):
80
- if hasattr(val, "to_dict"):
81
- val = val.to_dict()
82
- if val:
83
- struct[t] = val
84
- else:
85
- struct[t] = val
91
+
92
+ fields = self._resolve_initial_to_dict_fields(fields)
93
+ fields_to_exclude = exclude or []
94
+ if strip:
95
+ fields_to_exclude += self._default_fields_to_strip
96
+
97
+ # fields_to_save is built from the fields list minus the fields to exclude minus the fields that requires
98
+ # serialization and enrichment (because they will be added later to the struct)
99
+ fields_to_save = (
100
+ set(fields)
101
+ - set(fields_to_exclude)
102
+ - set(self._fields_to_serialize)
103
+ - set(self._fields_to_enrich)
104
+ )
105
+
106
+ # Iterating over the fields to save and adding them to the struct
107
+ for field_name in fields_to_save:
108
+ field_value = getattr(self, field_name, None)
109
+ if self._is_valid_field_value_for_serialization(
110
+ field_name, field_value, strip
111
+ ):
112
+ # If the field value has attribute to_dict, we call it.
113
+ # If one of the attributes is a third party object that has to_dict method (such as k8s objects), then
114
+ # add it to the object's _fields_to_serialize attribute and handle it in the _serialize_field method.
115
+ if hasattr(field_value, "to_dict"):
116
+ field_value = field_value.to_dict(strip=strip)
117
+ if self._is_valid_field_value_for_serialization(
118
+ field_name, field_value, strip
119
+ ):
120
+ struct[field_name] = field_value
121
+ else:
122
+ struct[field_name] = field_value
123
+
124
+ # Subtracting the fields_to_exclude from the fields_to_serialize because if we want to exclude a field there
125
+ # is no need to serialize it.
126
+ fields_to_serialize = list(
127
+ set(self._fields_to_serialize) - set(fields_to_exclude)
128
+ )
129
+ self._resolve_field_value_by_method(
130
+ struct, self._serialize_field, fields_to_serialize, strip
131
+ )
132
+
133
+ # Subtracting the fields_to_exclude from the fields_to_enrich because if we want to exclude a field there
134
+ # is no need to enrich it.
135
+ fields_to_enrich = list(set(self._fields_to_enrich) - set(fields_to_exclude))
136
+ self._resolve_field_value_by_method(
137
+ struct, self._enrich_field, fields_to_enrich, strip
138
+ )
139
+
140
+ self._apply_enrichment_before_to_dict_completion(struct, strip=strip)
141
+ return struct
142
+
143
+ def _resolve_initial_to_dict_fields(self, fields: list = None) -> list:
144
+ """
145
+ Resolve fields to be used in to_dict method.
146
+ If fields is None, use `_dict_fields` attribute of the object.
147
+ If fields is None and `_dict_fields` is empty, use the object's __init__ parameters.
148
+ :param fields: List of fields to iterate over.
149
+
150
+ :return: List of fields to iterate over.
151
+ """
152
+ return (
153
+ fields
154
+ or self._dict_fields
155
+ or list(inspect.signature(self.__init__).parameters.keys())
156
+ )
157
+
158
+ def _is_valid_field_value_for_serialization(
159
+ self, field_name: str, field_value: str, strip: bool = False
160
+ ) -> bool:
161
+ """
162
+ Check if the field value is valid for serialization.
163
+ If field name is in `_fields_to_skip_validation` attribute, skip validation and return True.
164
+ If strip is False skip validation and return True.
165
+ If field value is None or empty dict/list, then no need to store it.
166
+ :param field_name: Field name.
167
+ :param field_value: Field value.
168
+
169
+ :return: True if the field value is valid for serialization, False otherwise.
170
+ """
171
+ if field_name in self._fields_to_skip_validation:
172
+ return True
173
+ # TODO: remove when Runtime initialization will be refactored and enrichment will be moved to BE
174
+ # if not strip:
175
+ # return True
176
+
177
+ return field_value is not None and not (
178
+ (isinstance(field_value, dict) or isinstance(field_value, list))
179
+ and not field_value
180
+ )
181
+
182
+ def _resolve_field_value_by_method(
183
+ self,
184
+ struct: dict,
185
+ method: typing.Callable,
186
+ fields: typing.Union[list, set] = None,
187
+ strip: bool = False,
188
+ ) -> dict:
189
+ for field_name in fields:
190
+ field_value = method(struct=struct, field_name=field_name, strip=strip)
191
+ if self._is_valid_field_value_for_serialization(
192
+ field_name, field_value, strip
193
+ ):
194
+ struct[field_name] = field_value
195
+ return struct
196
+
197
+ def _serialize_field(
198
+ self, struct: dict, field_name: str = None, strip: bool = False
199
+ ) -> typing.Any:
200
+ # We pull the field from self and not from struct because it was excluded from the struct when looping over
201
+ # the fields to save.
202
+ return getattr(self, field_name, None)
203
+
204
+ def _enrich_field(
205
+ self, struct: dict, field_name: str = None, strip: bool = False
206
+ ) -> typing.Any:
207
+ # We first try to pull from struct because the field might have been already serialized and if not,
208
+ # we pull from self
209
+ return struct.get(field_name, None) or getattr(self, field_name, None)
210
+
211
+ def _apply_enrichment_before_to_dict_completion(
212
+ self, struct: dict, strip: bool = False
213
+ ) -> dict:
86
214
  return struct
87
215
 
88
216
  @classmethod
@@ -111,19 +239,21 @@ class ModelObj:
111
239
 
112
240
  return new_obj
113
241
 
114
- def to_yaml(self, exclude=None) -> str:
242
+ def to_yaml(self, exclude=None, strip: bool = False) -> str:
115
243
  """convert the object to yaml
116
244
 
117
245
  :param exclude: list of fields to exclude from the yaml
246
+ :param strip: if True, strip fields that are not required for actually define the object
118
247
  """
119
- return dict_to_yaml(self.to_dict(exclude=exclude))
248
+ return dict_to_yaml(self.to_dict(exclude=exclude, strip=strip))
120
249
 
121
- def to_json(self, exclude=None):
250
+ def to_json(self, exclude=None, strip: bool = False):
122
251
  """convert the object to json
123
252
 
124
253
  :param exclude: list of fields to exclude from the json
254
+ :param strip: if True, strip fields that are not required for actually define the object
125
255
  """
126
- return dict_to_json(self.to_dict(exclude=exclude))
256
+ return dict_to_json(self.to_dict(exclude=exclude, strip=strip))
127
257
 
128
258
  def to_str(self):
129
259
  """convert the object to string (with dict layout)"""
@@ -175,8 +305,8 @@ class ObjectDict:
175
305
  self._children[key] = child
176
306
  return child
177
307
 
178
- def to_dict(self):
179
- return {k: v.to_dict() for k, v in self._children.items()}
308
+ def to_dict(self, strip: bool = False):
309
+ return {k: v.to_dict(strip=strip) for k, v in self._children.items()}
180
310
 
181
311
  @classmethod
182
312
  def from_dict(cls, classes_map: dict, children=None, default_kind=""):
@@ -258,9 +388,9 @@ class ObjectList:
258
388
  def __delitem__(self, key):
259
389
  del self._children[key]
260
390
 
261
- def to_dict(self):
391
+ def to_dict(self, strip: bool = False):
262
392
  # method used by ModelObj class to serialize the object to nested dict
263
- return [t.to_dict() for t in self._children.values()]
393
+ return [t.to_dict(strip=strip) for t in self._children.values()]
264
394
 
265
395
  @classmethod
266
396
  def from_list(cls, child_class, children=None):
@@ -305,6 +435,18 @@ class Credentials(ModelObj):
305
435
 
306
436
 
307
437
  class BaseMetadata(ModelObj):
438
+ _default_fields_to_strip = ModelObj._default_fields_to_strip + [
439
+ "hash",
440
+ # Below are environment specific fields, no need to keep when stripping
441
+ "namespace",
442
+ "project",
443
+ "labels",
444
+ "annotations",
445
+ "credentials",
446
+ # Below are state fields, no need to keep when stripping
447
+ "updated",
448
+ ]
449
+
308
450
  def __init__(
309
451
  self,
310
452
  name=None,
@@ -449,7 +591,7 @@ class ImageBuilder(ModelObj):
449
591
 
450
592
  def with_commands(
451
593
  self,
452
- commands: List[str],
594
+ commands: list[str],
453
595
  overwrite: bool = False,
454
596
  ):
455
597
  """add commands to build spec.
@@ -476,7 +618,7 @@ class ImageBuilder(ModelObj):
476
618
 
477
619
  def with_requirements(
478
620
  self,
479
- requirements: Optional[List[str]] = None,
621
+ requirements: Optional[list[str]] = None,
480
622
  requirements_file: str = "",
481
623
  overwrite: bool = False,
482
624
  ):
@@ -509,7 +651,7 @@ class ImageBuilder(ModelObj):
509
651
 
510
652
  # handle the requirements_file argument
511
653
  if requirements_file:
512
- with open(requirements_file, "r") as fp:
654
+ with open(requirements_file) as fp:
513
655
  requirements_to_resolve.extend(fp.read().splitlines())
514
656
 
515
657
  # handle the requirements argument
@@ -540,10 +682,14 @@ class Notification(ModelObj):
540
682
 
541
683
  def __init__(
542
684
  self,
543
- kind=None,
685
+ kind: mlrun.common.schemas.notification.NotificationKind = (
686
+ mlrun.common.schemas.notification.NotificationKind.slack
687
+ ),
544
688
  name=None,
545
689
  message=None,
546
- severity=None,
690
+ severity: mlrun.common.schemas.notification.NotificationSeverity = (
691
+ mlrun.common.schemas.notification.NotificationSeverity.INFO
692
+ ),
547
693
  when=None,
548
694
  condition=None,
549
695
  secret_params=None,
@@ -552,12 +698,10 @@ class Notification(ModelObj):
552
698
  sent_time=None,
553
699
  reason=None,
554
700
  ):
555
- self.kind = kind or mlrun.common.schemas.notification.NotificationKind.slack
701
+ self.kind = kind
556
702
  self.name = name or ""
557
703
  self.message = message or ""
558
- self.severity = (
559
- severity or mlrun.common.schemas.notification.NotificationSeverity.INFO
560
- )
704
+ self.severity = severity
561
705
  self.when = when or ["completed"]
562
706
  self.condition = condition or ""
563
707
  self.secret_params = secret_params or {}
@@ -588,7 +732,7 @@ class Notification(ModelObj):
588
732
  )
589
733
 
590
734
  @staticmethod
591
- def validate_notification_uniqueness(notifications: List["Notification"]):
735
+ def validate_notification_uniqueness(notifications: list["Notification"]):
592
736
  """Validate that all notifications in the list are unique by name"""
593
737
  names = [notification.name for notification in notifications]
594
738
  if len(names) != len(set(names)):
@@ -627,7 +771,10 @@ class RunMetadata(ModelObj):
627
771
  def is_workflow_runner(self):
628
772
  if not self.labels:
629
773
  return False
630
- return self.labels.get("job-type", "") == "workflow-runner"
774
+ return (
775
+ self.labels.get(mlrun_constants.MLRunInternalLabels.job_type, "")
776
+ == "workflow-runner"
777
+ )
631
778
 
632
779
 
633
780
  class HyperParamStrategies:
@@ -697,6 +844,10 @@ class HyperParamOptions(ModelObj):
697
844
  class RunSpec(ModelObj):
698
845
  """Run specification"""
699
846
 
847
+ _fields_to_serialize = ModelObj._fields_to_serialize + [
848
+ "handler",
849
+ ]
850
+
700
851
  def __init__(
701
852
  self,
702
853
  parameters=None,
@@ -757,18 +908,22 @@ class RunSpec(ModelObj):
757
908
  self._notifications = notifications or []
758
909
  self.state_thresholds = state_thresholds or {}
759
910
 
760
- def to_dict(self, fields=None, exclude=None):
761
- struct = super().to_dict(fields, exclude=["handler"])
762
- if self.handler and isinstance(self.handler, str):
763
- struct["handler"] = self.handler
764
- return struct
911
+ def _serialize_field(
912
+ self, struct: dict, field_name: str = None, strip: bool = False
913
+ ) -> Optional[str]:
914
+ # We pull the field from self and not from struct because it was excluded from the struct
915
+ if field_name == "handler":
916
+ if self.handler and isinstance(self.handler, str):
917
+ return self.handler
918
+ return None
919
+ return super()._serialize_field(struct, field_name, strip)
765
920
 
766
921
  def is_hyper_job(self):
767
922
  param_file = self.param_file or self.hyper_param_options.param_file
768
923
  return param_file or self.hyperparams
769
924
 
770
925
  @property
771
- def inputs(self) -> Dict[str, str]:
926
+ def inputs(self) -> dict[str, str]:
772
927
  """
773
928
  Get the inputs dictionary. A dictionary of parameter names as keys and paths as values.
774
929
 
@@ -777,7 +932,7 @@ class RunSpec(ModelObj):
777
932
  return self._inputs
778
933
 
779
934
  @inputs.setter
780
- def inputs(self, inputs: Dict[str, str]):
935
+ def inputs(self, inputs: dict[str, str]):
781
936
  """
782
937
  Set the given inputs in the spec. Inputs can include a type hint string in their keys following a colon, meaning
783
938
  following this structure: "<input key : type hint>".
@@ -786,7 +941,7 @@ class RunSpec(ModelObj):
786
941
 
787
942
  >>> run_spec.inputs = {
788
943
  ... "my_input": "...",
789
- ... "my_hinted_input : pandas.DataFrame": "..."
944
+ ... "my_hinted_input : pandas.DataFrame": "...",
790
945
  ... }
791
946
 
792
947
  :param inputs: The inputs to set.
@@ -800,7 +955,7 @@ class RunSpec(ModelObj):
800
955
  self._inputs = self._verify_dict(inputs, "inputs")
801
956
 
802
957
  @property
803
- def inputs_type_hints(self) -> Dict[str, str]:
958
+ def inputs_type_hints(self) -> dict[str, str]:
804
959
  """
805
960
  Get the input type hints. A dictionary of parameter names as keys and their type hints as values.
806
961
 
@@ -809,7 +964,7 @@ class RunSpec(ModelObj):
809
964
  return self._inputs_type_hints
810
965
 
811
966
  @inputs_type_hints.setter
812
- def inputs_type_hints(self, inputs_type_hints: Dict[str, str]):
967
+ def inputs_type_hints(self, inputs_type_hints: dict[str, str]):
813
968
  """
814
969
  Set the inputs type hints to parse during a run.
815
970
 
@@ -830,7 +985,7 @@ class RunSpec(ModelObj):
830
985
  return self._returns
831
986
 
832
987
  @returns.setter
833
- def returns(self, returns: List[Union[str, Dict[str, str]]]):
988
+ def returns(self, returns: list[Union[str, dict[str, str]]]):
834
989
  """
835
990
  Set the returns list to log the returning values at the end of a run.
836
991
 
@@ -864,7 +1019,7 @@ class RunSpec(ModelObj):
864
1019
  )
865
1020
 
866
1021
  @property
867
- def outputs(self) -> List[str]:
1022
+ def outputs(self) -> list[str]:
868
1023
  """
869
1024
  Get the expected outputs. The list is constructed from keys of both the `outputs` and `returns` properties.
870
1025
 
@@ -929,7 +1084,7 @@ class RunSpec(ModelObj):
929
1084
  return self._state_thresholds
930
1085
 
931
1086
  @state_thresholds.setter
932
- def state_thresholds(self, state_thresholds: Dict[str, str]):
1087
+ def state_thresholds(self, state_thresholds: dict[str, str]):
933
1088
  """
934
1089
  Set the dictionary of k8s resource states to thresholds time strings.
935
1090
  The state will be matched against the pod's status. The threshold should be a time string that conforms
@@ -981,8 +1136,8 @@ class RunSpec(ModelObj):
981
1136
 
982
1137
  @staticmethod
983
1138
  def join_outputs_and_returns(
984
- outputs: List[str], returns: List[Union[str, Dict[str, str]]]
985
- ) -> List[str]:
1139
+ outputs: list[str], returns: list[Union[str, dict[str, str]]]
1140
+ ) -> list[str]:
986
1141
  """
987
1142
  Get the outputs set in the spec. The outputs are constructed from both the 'outputs' and 'returns' properties
988
1143
  that were set by the user.
@@ -1013,7 +1168,7 @@ class RunSpec(ModelObj):
1013
1168
  return outputs
1014
1169
 
1015
1170
  @staticmethod
1016
- def _separate_type_hint_from_input_key(input_key: str) -> Tuple[str, str]:
1171
+ def _separate_type_hint_from_input_key(input_key: str) -> tuple[str, str]:
1017
1172
  """
1018
1173
  An input key in the `inputs` dictionary parameter of a task (or `Runtime.run` method) or the docs setting of a
1019
1174
  `Runtime` handler can be provided with a colon to specify its type hint in the following structure:
@@ -1057,7 +1212,7 @@ class RunStatus(ModelObj):
1057
1212
  iterations=None,
1058
1213
  ui_url=None,
1059
1214
  reason: str = None,
1060
- notifications: Dict[str, Notification] = None,
1215
+ notifications: dict[str, Notification] = None,
1061
1216
  artifact_uris: dict[str, str] = None,
1062
1217
  ):
1063
1218
  self.state = state or "created"
@@ -1146,7 +1301,7 @@ class RunTemplate(ModelObj):
1146
1301
 
1147
1302
  example::
1148
1303
 
1149
- grid_params = {"p1": [2,4,1], "p2": [10,20]}
1304
+ grid_params = {"p1": [2, 4, 1], "p2": [10, 20]}
1150
1305
  task = mlrun.new_task("grid-search")
1151
1306
  task.with_hyper_params(grid_params, selector="max.accuracy")
1152
1307
  """
@@ -1288,11 +1443,14 @@ class RunObject(RunTemplate):
1288
1443
  unknown_error = ""
1289
1444
  if (
1290
1445
  self.status.state
1291
- in mlrun.runtimes.constants.RunStates.abortion_states()
1446
+ in mlrun.common.runtimes.constants.RunStates.abortion_states()
1292
1447
  ):
1293
1448
  unknown_error = "Run was aborted"
1294
1449
 
1295
- elif self.status.state in mlrun.runtimes.constants.RunStates.error_states():
1450
+ elif (
1451
+ self.status.state
1452
+ in mlrun.common.runtimes.constants.RunStates.error_states()
1453
+ ):
1296
1454
  unknown_error = "Unknown error"
1297
1455
 
1298
1456
  return (
@@ -1318,7 +1476,7 @@ class RunObject(RunTemplate):
1318
1476
  """UI URL (for relevant runtimes)"""
1319
1477
  self.refresh()
1320
1478
  if not self._status.ui_url:
1321
- print("UI currently not available (status={})".format(self._status.state))
1479
+ print(f"UI currently not available (status={self._status.state})")
1322
1480
  return self._status.ui_url
1323
1481
 
1324
1482
  @property
@@ -1330,7 +1488,7 @@ class RunObject(RunTemplate):
1330
1488
  outputs = {k: v for k, v in self.status.results.items()}
1331
1489
  if self.status.artifacts:
1332
1490
  for a in self.status.artifacts:
1333
- key = a["key"] if is_legacy_artifact(a) else a["metadata"]["key"]
1491
+ key = a["metadata"]["key"]
1334
1492
  outputs[key] = get_artifact_target(a, self.metadata.project)
1335
1493
  return outputs
1336
1494
 
@@ -1373,7 +1531,10 @@ class RunObject(RunTemplate):
1373
1531
 
1374
1532
  def state(self):
1375
1533
  """current run state"""
1376
- if self.status.state in mlrun.runtimes.constants.RunStates.terminal_states():
1534
+ if (
1535
+ self.status.state
1536
+ in mlrun.common.runtimes.constants.RunStates.terminal_states()
1537
+ ):
1377
1538
  return self.status.state
1378
1539
  self.refresh()
1379
1540
  return self.status.state or "unknown"
@@ -1437,7 +1598,7 @@ class RunObject(RunTemplate):
1437
1598
  last_pull_log_time = None
1438
1599
  logs_enabled = show_logs is not False
1439
1600
  state = self.state()
1440
- if state not in mlrun.runtimes.constants.RunStates.terminal_states():
1601
+ if state not in mlrun.common.runtimes.constants.RunStates.terminal_states():
1441
1602
  logger.info(
1442
1603
  f"run {self.metadata.name} is not completed yet, waiting for it to complete",
1443
1604
  current_state=state,
@@ -1447,7 +1608,8 @@ class RunObject(RunTemplate):
1447
1608
  if (
1448
1609
  logs_enabled
1449
1610
  and logs_interval
1450
- and state not in mlrun.runtimes.constants.RunStates.terminal_states()
1611
+ and state
1612
+ not in mlrun.common.runtimes.constants.RunStates.terminal_states()
1451
1613
  and (
1452
1614
  last_pull_log_time is None
1453
1615
  or (datetime.now() - last_pull_log_time).seconds > logs_interval
@@ -1456,7 +1618,7 @@ class RunObject(RunTemplate):
1456
1618
  last_pull_log_time = datetime.now()
1457
1619
  state, offset = self.logs(watch=False, offset=offset)
1458
1620
 
1459
- if state in mlrun.runtimes.constants.RunStates.terminal_states():
1621
+ if state in mlrun.common.runtimes.constants.RunStates.terminal_states():
1460
1622
  if logs_enabled and logs_interval:
1461
1623
  self.logs(watch=False, offset=offset)
1462
1624
  break
@@ -1468,7 +1630,10 @@ class RunObject(RunTemplate):
1468
1630
  )
1469
1631
  if logs_enabled and not logs_interval:
1470
1632
  self.logs(watch=False)
1471
- if raise_on_failure and state != mlrun.runtimes.constants.RunStates.completed:
1633
+ if (
1634
+ raise_on_failure
1635
+ and state != mlrun.common.runtimes.constants.RunStates.completed
1636
+ ):
1472
1637
  raise mlrun.errors.MLRunRuntimeError(
1473
1638
  f"Task {self.metadata.name} did not complete (state={state})"
1474
1639
  )
@@ -1483,7 +1648,7 @@ class RunObject(RunTemplate):
1483
1648
  return f"{project}@{uid}#{iteration}{tag}"
1484
1649
 
1485
1650
  @staticmethod
1486
- def parse_uri(uri: str) -> Tuple[str, str, str, str]:
1651
+ def parse_uri(uri: str) -> tuple[str, str, str, str]:
1487
1652
  uri_pattern = (
1488
1653
  r"^(?P<project>.*)@(?P<uid>.*)\#(?P<iteration>.*?)(:(?P<tag>.*))?$"
1489
1654
  )
@@ -1704,7 +1869,7 @@ class DataSource(ModelObj):
1704
1869
  self,
1705
1870
  name: str = None,
1706
1871
  path: str = None,
1707
- attributes: Dict[str, object] = None,
1872
+ attributes: dict[str, object] = None,
1708
1873
  key_field: str = None,
1709
1874
  time_field: str = None,
1710
1875
  schedule: str = None,
@@ -1770,16 +1935,16 @@ class DataTargetBase(ModelObj):
1770
1935
  kind: str = None,
1771
1936
  name: str = "",
1772
1937
  path=None,
1773
- attributes: Dict[str, str] = None,
1938
+ attributes: dict[str, str] = None,
1774
1939
  after_step=None,
1775
1940
  partitioned: bool = False,
1776
1941
  key_bucketing_number: Optional[int] = None,
1777
- partition_cols: Optional[List[str]] = None,
1942
+ partition_cols: Optional[list[str]] = None,
1778
1943
  time_partitioning_granularity: Optional[str] = None,
1779
1944
  max_events: Optional[int] = None,
1780
1945
  flush_after_seconds: Optional[int] = None,
1781
- storage_options: Dict[str, str] = None,
1782
- schema: Dict[str, Any] = None,
1946
+ storage_options: dict[str, str] = None,
1947
+ schema: dict[str, Any] = None,
1783
1948
  credentials_prefix=None,
1784
1949
  ):
1785
1950
  self.name = name
@@ -1866,8 +2031,8 @@ class VersionedObjMetadata(ModelObj):
1866
2031
  tag: str = None,
1867
2032
  uid: str = None,
1868
2033
  project: str = None,
1869
- labels: Dict[str, str] = None,
1870
- annotations: Dict[str, str] = None,
2034
+ labels: dict[str, str] = None,
2035
+ annotations: dict[str, str] = None,
1871
2036
  updated=None,
1872
2037
  ):
1873
2038
  self.name = name
@@ -15,7 +15,7 @@
15
15
  # flake8: noqa - this is until we take care of the F401 violations with respect to __all__ & sphinx
16
16
  # for backwards compatibility
17
17
 
18
+ from .db import get_store_object, get_tsdb_connector
18
19
  from .helpers import get_stream_path
19
20
  from .model_endpoint import ModelEndpoint
20
- from .stores import ModelEndpointStore, ModelEndpointStoreType, get_model_endpoint_store
21
21
  from .tracking_policy import TrackingPolicy