mlrun 1.6.4rc8__py3-none-any.whl → 1.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mlrun might be problematic. Click here for more details.

Files changed (305) hide show
  1. mlrun/__init__.py +11 -1
  2. mlrun/__main__.py +40 -122
  3. mlrun/alerts/__init__.py +15 -0
  4. mlrun/alerts/alert.py +248 -0
  5. mlrun/api/schemas/__init__.py +5 -4
  6. mlrun/artifacts/__init__.py +8 -3
  7. mlrun/artifacts/base.py +47 -257
  8. mlrun/artifacts/dataset.py +11 -192
  9. mlrun/artifacts/manager.py +79 -47
  10. mlrun/artifacts/model.py +31 -159
  11. mlrun/artifacts/plots.py +23 -380
  12. mlrun/common/constants.py +74 -1
  13. mlrun/common/db/sql_session.py +5 -5
  14. mlrun/common/formatters/__init__.py +21 -0
  15. mlrun/common/formatters/artifact.py +45 -0
  16. mlrun/common/formatters/base.py +113 -0
  17. mlrun/common/formatters/feature_set.py +33 -0
  18. mlrun/common/formatters/function.py +46 -0
  19. mlrun/common/formatters/pipeline.py +53 -0
  20. mlrun/common/formatters/project.py +51 -0
  21. mlrun/common/formatters/run.py +29 -0
  22. mlrun/common/helpers.py +12 -3
  23. mlrun/common/model_monitoring/helpers.py +9 -5
  24. mlrun/{runtimes → common/runtimes}/constants.py +37 -9
  25. mlrun/common/schemas/__init__.py +31 -5
  26. mlrun/common/schemas/alert.py +202 -0
  27. mlrun/common/schemas/api_gateway.py +196 -0
  28. mlrun/common/schemas/artifact.py +25 -4
  29. mlrun/common/schemas/auth.py +16 -5
  30. mlrun/common/schemas/background_task.py +1 -1
  31. mlrun/common/schemas/client_spec.py +4 -2
  32. mlrun/common/schemas/common.py +7 -4
  33. mlrun/common/schemas/constants.py +3 -0
  34. mlrun/common/schemas/feature_store.py +74 -44
  35. mlrun/common/schemas/frontend_spec.py +15 -7
  36. mlrun/common/schemas/function.py +12 -1
  37. mlrun/common/schemas/hub.py +11 -18
  38. mlrun/common/schemas/memory_reports.py +2 -2
  39. mlrun/common/schemas/model_monitoring/__init__.py +20 -4
  40. mlrun/common/schemas/model_monitoring/constants.py +123 -42
  41. mlrun/common/schemas/model_monitoring/grafana.py +13 -9
  42. mlrun/common/schemas/model_monitoring/model_endpoints.py +101 -54
  43. mlrun/common/schemas/notification.py +71 -14
  44. mlrun/common/schemas/object.py +2 -2
  45. mlrun/{model_monitoring/controller_handler.py → common/schemas/pagination.py} +9 -12
  46. mlrun/common/schemas/pipeline.py +8 -1
  47. mlrun/common/schemas/project.py +69 -18
  48. mlrun/common/schemas/runs.py +7 -1
  49. mlrun/common/schemas/runtime_resource.py +8 -12
  50. mlrun/common/schemas/schedule.py +4 -4
  51. mlrun/common/schemas/tag.py +1 -2
  52. mlrun/common/schemas/workflow.py +12 -4
  53. mlrun/common/types.py +14 -1
  54. mlrun/config.py +154 -69
  55. mlrun/data_types/data_types.py +6 -1
  56. mlrun/data_types/spark.py +2 -2
  57. mlrun/data_types/to_pandas.py +67 -37
  58. mlrun/datastore/__init__.py +6 -8
  59. mlrun/datastore/alibaba_oss.py +131 -0
  60. mlrun/datastore/azure_blob.py +143 -42
  61. mlrun/datastore/base.py +102 -58
  62. mlrun/datastore/datastore.py +34 -13
  63. mlrun/datastore/datastore_profile.py +146 -20
  64. mlrun/datastore/dbfs_store.py +3 -7
  65. mlrun/datastore/filestore.py +1 -4
  66. mlrun/datastore/google_cloud_storage.py +97 -33
  67. mlrun/datastore/hdfs.py +56 -0
  68. mlrun/datastore/inmem.py +6 -3
  69. mlrun/datastore/redis.py +7 -2
  70. mlrun/datastore/s3.py +34 -12
  71. mlrun/datastore/snowflake_utils.py +45 -0
  72. mlrun/datastore/sources.py +303 -111
  73. mlrun/datastore/spark_utils.py +31 -2
  74. mlrun/datastore/store_resources.py +9 -7
  75. mlrun/datastore/storeytargets.py +151 -0
  76. mlrun/datastore/targets.py +453 -176
  77. mlrun/datastore/utils.py +72 -58
  78. mlrun/datastore/v3io.py +6 -1
  79. mlrun/db/base.py +274 -41
  80. mlrun/db/factory.py +1 -1
  81. mlrun/db/httpdb.py +893 -225
  82. mlrun/db/nopdb.py +291 -33
  83. mlrun/errors.py +36 -6
  84. mlrun/execution.py +115 -42
  85. mlrun/feature_store/__init__.py +0 -2
  86. mlrun/feature_store/api.py +65 -73
  87. mlrun/feature_store/common.py +7 -12
  88. mlrun/feature_store/feature_set.py +76 -55
  89. mlrun/feature_store/feature_vector.py +39 -31
  90. mlrun/feature_store/ingestion.py +7 -6
  91. mlrun/feature_store/retrieval/base.py +16 -11
  92. mlrun/feature_store/retrieval/dask_merger.py +2 -0
  93. mlrun/feature_store/retrieval/job.py +13 -4
  94. mlrun/feature_store/retrieval/local_merger.py +2 -0
  95. mlrun/feature_store/retrieval/spark_merger.py +24 -32
  96. mlrun/feature_store/steps.py +45 -34
  97. mlrun/features.py +11 -21
  98. mlrun/frameworks/_common/artifacts_library.py +9 -9
  99. mlrun/frameworks/_common/mlrun_interface.py +5 -5
  100. mlrun/frameworks/_common/model_handler.py +48 -48
  101. mlrun/frameworks/_common/plan.py +5 -6
  102. mlrun/frameworks/_common/producer.py +3 -4
  103. mlrun/frameworks/_common/utils.py +5 -5
  104. mlrun/frameworks/_dl_common/loggers/logger.py +6 -7
  105. mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +9 -9
  106. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +23 -47
  107. mlrun/frameworks/_ml_common/artifacts_library.py +1 -2
  108. mlrun/frameworks/_ml_common/loggers/logger.py +3 -4
  109. mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +4 -5
  110. mlrun/frameworks/_ml_common/model_handler.py +24 -24
  111. mlrun/frameworks/_ml_common/pkl_model_server.py +2 -2
  112. mlrun/frameworks/_ml_common/plan.py +2 -2
  113. mlrun/frameworks/_ml_common/plans/calibration_curve_plan.py +2 -3
  114. mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +2 -3
  115. mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
  116. mlrun/frameworks/_ml_common/plans/feature_importance_plan.py +3 -3
  117. mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
  118. mlrun/frameworks/_ml_common/utils.py +4 -4
  119. mlrun/frameworks/auto_mlrun/auto_mlrun.py +9 -9
  120. mlrun/frameworks/huggingface/model_server.py +4 -4
  121. mlrun/frameworks/lgbm/__init__.py +33 -33
  122. mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
  123. mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -5
  124. mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -5
  125. mlrun/frameworks/lgbm/mlrun_interfaces/booster_mlrun_interface.py +1 -3
  126. mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +6 -6
  127. mlrun/frameworks/lgbm/model_handler.py +10 -10
  128. mlrun/frameworks/lgbm/model_server.py +6 -6
  129. mlrun/frameworks/lgbm/utils.py +5 -5
  130. mlrun/frameworks/onnx/dataset.py +8 -8
  131. mlrun/frameworks/onnx/mlrun_interface.py +3 -3
  132. mlrun/frameworks/onnx/model_handler.py +6 -6
  133. mlrun/frameworks/onnx/model_server.py +7 -7
  134. mlrun/frameworks/parallel_coordinates.py +6 -6
  135. mlrun/frameworks/pytorch/__init__.py +18 -18
  136. mlrun/frameworks/pytorch/callbacks/callback.py +4 -5
  137. mlrun/frameworks/pytorch/callbacks/logging_callback.py +17 -17
  138. mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +11 -11
  139. mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +23 -29
  140. mlrun/frameworks/pytorch/callbacks_handler.py +38 -38
  141. mlrun/frameworks/pytorch/mlrun_interface.py +20 -20
  142. mlrun/frameworks/pytorch/model_handler.py +17 -17
  143. mlrun/frameworks/pytorch/model_server.py +7 -7
  144. mlrun/frameworks/sklearn/__init__.py +13 -13
  145. mlrun/frameworks/sklearn/estimator.py +4 -4
  146. mlrun/frameworks/sklearn/metrics_library.py +14 -14
  147. mlrun/frameworks/sklearn/mlrun_interface.py +16 -9
  148. mlrun/frameworks/sklearn/model_handler.py +2 -2
  149. mlrun/frameworks/tf_keras/__init__.py +10 -7
  150. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +15 -15
  151. mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +11 -11
  152. mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +19 -23
  153. mlrun/frameworks/tf_keras/mlrun_interface.py +9 -11
  154. mlrun/frameworks/tf_keras/model_handler.py +14 -14
  155. mlrun/frameworks/tf_keras/model_server.py +6 -6
  156. mlrun/frameworks/xgboost/__init__.py +13 -13
  157. mlrun/frameworks/xgboost/model_handler.py +6 -6
  158. mlrun/k8s_utils.py +61 -17
  159. mlrun/launcher/__init__.py +1 -1
  160. mlrun/launcher/base.py +16 -15
  161. mlrun/launcher/client.py +13 -11
  162. mlrun/launcher/factory.py +1 -1
  163. mlrun/launcher/local.py +23 -13
  164. mlrun/launcher/remote.py +17 -10
  165. mlrun/lists.py +7 -6
  166. mlrun/model.py +478 -103
  167. mlrun/model_monitoring/__init__.py +1 -1
  168. mlrun/model_monitoring/api.py +163 -371
  169. mlrun/{runtimes/mpijob/v1alpha1.py → model_monitoring/applications/__init__.py} +9 -15
  170. mlrun/model_monitoring/applications/_application_steps.py +188 -0
  171. mlrun/model_monitoring/applications/base.py +108 -0
  172. mlrun/model_monitoring/applications/context.py +341 -0
  173. mlrun/model_monitoring/{evidently_application.py → applications/evidently_base.py} +27 -22
  174. mlrun/model_monitoring/applications/histogram_data_drift.py +354 -0
  175. mlrun/model_monitoring/applications/results.py +99 -0
  176. mlrun/model_monitoring/controller.py +131 -278
  177. mlrun/model_monitoring/db/__init__.py +18 -0
  178. mlrun/model_monitoring/db/stores/__init__.py +136 -0
  179. mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
  180. mlrun/model_monitoring/db/stores/base/store.py +213 -0
  181. mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
  182. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
  183. mlrun/model_monitoring/db/stores/sqldb/models/base.py +190 -0
  184. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +103 -0
  185. mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
  186. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +659 -0
  187. mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
  188. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +726 -0
  189. mlrun/model_monitoring/db/tsdb/__init__.py +105 -0
  190. mlrun/model_monitoring/db/tsdb/base.py +448 -0
  191. mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
  192. mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
  193. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +279 -0
  194. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +42 -0
  195. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +507 -0
  196. mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
  197. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +158 -0
  198. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +849 -0
  199. mlrun/model_monitoring/features_drift_table.py +134 -106
  200. mlrun/model_monitoring/helpers.py +199 -55
  201. mlrun/model_monitoring/metrics/__init__.py +13 -0
  202. mlrun/model_monitoring/metrics/histogram_distance.py +127 -0
  203. mlrun/model_monitoring/model_endpoint.py +3 -2
  204. mlrun/model_monitoring/stream_processing.py +134 -398
  205. mlrun/model_monitoring/tracking_policy.py +9 -2
  206. mlrun/model_monitoring/writer.py +161 -125
  207. mlrun/package/__init__.py +6 -6
  208. mlrun/package/context_handler.py +5 -5
  209. mlrun/package/packager.py +7 -7
  210. mlrun/package/packagers/default_packager.py +8 -8
  211. mlrun/package/packagers/numpy_packagers.py +15 -15
  212. mlrun/package/packagers/pandas_packagers.py +5 -5
  213. mlrun/package/packagers/python_standard_library_packagers.py +10 -10
  214. mlrun/package/packagers_manager.py +19 -23
  215. mlrun/package/utils/_formatter.py +6 -6
  216. mlrun/package/utils/_pickler.py +2 -2
  217. mlrun/package/utils/_supported_format.py +4 -4
  218. mlrun/package/utils/log_hint_utils.py +2 -2
  219. mlrun/package/utils/type_hint_utils.py +4 -9
  220. mlrun/platforms/__init__.py +11 -10
  221. mlrun/platforms/iguazio.py +24 -203
  222. mlrun/projects/operations.py +52 -25
  223. mlrun/projects/pipelines.py +191 -197
  224. mlrun/projects/project.py +1227 -400
  225. mlrun/render.py +16 -19
  226. mlrun/run.py +209 -184
  227. mlrun/runtimes/__init__.py +83 -15
  228. mlrun/runtimes/base.py +51 -35
  229. mlrun/runtimes/daskjob.py +17 -10
  230. mlrun/runtimes/databricks_job/databricks_cancel_task.py +1 -1
  231. mlrun/runtimes/databricks_job/databricks_runtime.py +8 -7
  232. mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
  233. mlrun/runtimes/funcdoc.py +1 -29
  234. mlrun/runtimes/function_reference.py +1 -1
  235. mlrun/runtimes/kubejob.py +34 -128
  236. mlrun/runtimes/local.py +40 -11
  237. mlrun/runtimes/mpijob/__init__.py +0 -20
  238. mlrun/runtimes/mpijob/abstract.py +9 -10
  239. mlrun/runtimes/mpijob/v1.py +1 -1
  240. mlrun/{model_monitoring/stores/models/sqlite.py → runtimes/nuclio/__init__.py} +7 -9
  241. mlrun/runtimes/nuclio/api_gateway.py +769 -0
  242. mlrun/runtimes/nuclio/application/__init__.py +15 -0
  243. mlrun/runtimes/nuclio/application/application.py +758 -0
  244. mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
  245. mlrun/runtimes/{function.py → nuclio/function.py} +200 -83
  246. mlrun/runtimes/{nuclio.py → nuclio/nuclio.py} +6 -6
  247. mlrun/runtimes/{serving.py → nuclio/serving.py} +65 -68
  248. mlrun/runtimes/pod.py +281 -101
  249. mlrun/runtimes/remotesparkjob.py +12 -9
  250. mlrun/runtimes/sparkjob/spark3job.py +67 -51
  251. mlrun/runtimes/utils.py +41 -75
  252. mlrun/secrets.py +9 -5
  253. mlrun/serving/__init__.py +8 -1
  254. mlrun/serving/remote.py +2 -7
  255. mlrun/serving/routers.py +85 -69
  256. mlrun/serving/server.py +69 -44
  257. mlrun/serving/states.py +209 -36
  258. mlrun/serving/utils.py +22 -14
  259. mlrun/serving/v1_serving.py +6 -7
  260. mlrun/serving/v2_serving.py +133 -54
  261. mlrun/track/tracker.py +2 -1
  262. mlrun/track/tracker_manager.py +3 -3
  263. mlrun/track/trackers/mlflow_tracker.py +6 -2
  264. mlrun/utils/async_http.py +6 -8
  265. mlrun/utils/azure_vault.py +1 -1
  266. mlrun/utils/clones.py +1 -2
  267. mlrun/utils/condition_evaluator.py +3 -3
  268. mlrun/utils/db.py +21 -3
  269. mlrun/utils/helpers.py +405 -225
  270. mlrun/utils/http.py +3 -6
  271. mlrun/utils/logger.py +112 -16
  272. mlrun/utils/notifications/notification/__init__.py +17 -13
  273. mlrun/utils/notifications/notification/base.py +50 -2
  274. mlrun/utils/notifications/notification/console.py +2 -0
  275. mlrun/utils/notifications/notification/git.py +24 -1
  276. mlrun/utils/notifications/notification/ipython.py +3 -1
  277. mlrun/utils/notifications/notification/slack.py +96 -21
  278. mlrun/utils/notifications/notification/webhook.py +59 -2
  279. mlrun/utils/notifications/notification_pusher.py +149 -30
  280. mlrun/utils/regex.py +9 -0
  281. mlrun/utils/retryer.py +208 -0
  282. mlrun/utils/singleton.py +1 -1
  283. mlrun/utils/v3io_clients.py +4 -6
  284. mlrun/utils/version/version.json +2 -2
  285. mlrun/utils/version/version.py +2 -6
  286. mlrun-1.7.0.dist-info/METADATA +378 -0
  287. mlrun-1.7.0.dist-info/RECORD +351 -0
  288. {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/WHEEL +1 -1
  289. mlrun/feature_store/retrieval/conversion.py +0 -273
  290. mlrun/kfpops.py +0 -868
  291. mlrun/model_monitoring/application.py +0 -310
  292. mlrun/model_monitoring/batch.py +0 -1095
  293. mlrun/model_monitoring/prometheus.py +0 -219
  294. mlrun/model_monitoring/stores/__init__.py +0 -111
  295. mlrun/model_monitoring/stores/kv_model_endpoint_store.py +0 -576
  296. mlrun/model_monitoring/stores/model_endpoint_store.py +0 -147
  297. mlrun/model_monitoring/stores/models/__init__.py +0 -27
  298. mlrun/model_monitoring/stores/models/base.py +0 -84
  299. mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -384
  300. mlrun/platforms/other.py +0 -306
  301. mlrun-1.6.4rc8.dist-info/METADATA +0 -272
  302. mlrun-1.6.4rc8.dist-info/RECORD +0 -314
  303. {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/LICENSE +0 -0
  304. {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/entry_points.txt +0 -0
  305. {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/top_level.txt +0 -0
@@ -15,12 +15,13 @@
15
15
  import threading
16
16
  import time
17
17
  import traceback
18
- from typing import Dict, Union
18
+ from typing import Optional, Union
19
19
 
20
- import mlrun.common.model_monitoring
20
+ import mlrun.artifacts
21
+ import mlrun.common.model_monitoring.helpers
21
22
  import mlrun.common.schemas.model_monitoring
22
- from mlrun.artifacts import ModelArtifact # noqa: F401
23
- from mlrun.config import config
23
+ import mlrun.model_monitoring
24
+ from mlrun.errors import err_to_str
24
25
  from mlrun.utils import logger, now_date
25
26
 
26
27
  from ..common.helpers import parse_versioned_object_uri
@@ -29,8 +30,6 @@ from .utils import StepToDict, _extract_input_data, _update_result_body
29
30
 
30
31
 
31
32
  class V2ModelServer(StepToDict):
32
- """base model serving class (v2), using similar API to KFServing v2 and Triton"""
33
-
34
33
  def __init__(
35
34
  self,
36
35
  context=None,
@@ -64,11 +63,11 @@ class V2ModelServer(StepToDict):
64
63
  class MyClass(V2ModelServer):
65
64
  def load(self):
66
65
  # load and initialize the model and/or other elements
67
- model_file, extra_data = self.get_model(suffix='.pkl')
66
+ model_file, extra_data = self.get_model(suffix=".pkl")
68
67
  self.model = load(open(model_file, "rb"))
69
68
 
70
69
  def predict(self, request):
71
- events = np.array(request['inputs'])
70
+ events = np.array(request["inputs"])
72
71
  dmatrix = xgb.DMatrix(events)
73
72
  result: xgb.DMatrix = self.model.predict(dmatrix)
74
73
  return {"outputs": result.tolist()}
@@ -103,7 +102,7 @@ class V2ModelServer(StepToDict):
103
102
  self.error = ""
104
103
  self.protocol = protocol or "v2"
105
104
  self.model_path = model_path
106
- self.model_spec: mlrun.artifacts.ModelArtifact = None
105
+ self.model_spec: Optional[mlrun.artifacts.ModelArtifact] = None
107
106
  self._input_path = input_path
108
107
  self._result_path = result_path
109
108
  self._kwargs = kwargs # for to_dict()
@@ -149,7 +148,7 @@ class V2ModelServer(StepToDict):
149
148
  logger.warn("GraphServer not initialized for VotingEnsemble instance")
150
149
  return
151
150
 
152
- if not self.context.is_mock or self.context.server.track_models:
151
+ if not self.context.is_mock or self.context.monitoring_mock:
153
152
  self.model_endpoint_uid = _init_endpoint_record(
154
153
  graph_server=server, model=self
155
154
  )
@@ -177,9 +176,9 @@ class V2ModelServer(StepToDict):
177
176
  ::
178
177
 
179
178
  def load(self):
180
- model_file, extra_data = self.get_model(suffix='.pkl')
179
+ model_file, extra_data = self.get_model(suffix=".pkl")
181
180
  self.model = load(open(model_file, "rb"))
182
- categories = extra_data['categories'].as_df()
181
+ categories = extra_data["categories"].as_df()
183
182
 
184
183
  Parameters
185
184
  ----------
@@ -221,6 +220,8 @@ class V2ModelServer(StepToDict):
221
220
 
222
221
  def _pre_event_processing_actions(self, event, event_body, op):
223
222
  self._check_readiness(event)
223
+ if "_dict" in op:
224
+ event_body = self._inputs_to_list(event_body)
224
225
  request = self.preprocess(event_body, op)
225
226
  return self.validate(request, op)
226
227
 
@@ -237,7 +238,12 @@ class V2ModelServer(StepToDict):
237
238
  if not op and event.method != "GET":
238
239
  op = "infer"
239
240
 
240
- if op == "predict" or op == "infer":
241
+ if (
242
+ op == "predict"
243
+ or op == "infer"
244
+ or op == "infer_dict"
245
+ or op == "predict_dict"
246
+ ):
241
247
  # predict operation
242
248
  request = self._pre_event_processing_actions(event, event_body, op)
243
249
  try:
@@ -252,6 +258,7 @@ class V2ModelServer(StepToDict):
252
258
  "id": event_id,
253
259
  "model_name": self.name,
254
260
  "outputs": outputs,
261
+ "timestamp": start.isoformat(sep=" ", timespec="microseconds"),
255
262
  }
256
263
  if self.version:
257
264
  response["model_version"] = self.version
@@ -329,6 +336,7 @@ class V2ModelServer(StepToDict):
329
336
  else:
330
337
  track_request = {"id": event_id, "inputs": inputs or []}
331
338
  track_response = {"outputs": outputs or []}
339
+ # TODO : check dict/list
332
340
  self._model_logger.push(start, track_request, track_response, op)
333
341
  event.body = _update_result_body(self._result_path, original_body, response)
334
342
  return event
@@ -362,22 +370,61 @@ class V2ModelServer(StepToDict):
362
370
 
363
371
  return request
364
372
 
365
- def preprocess(self, request: Dict, operation) -> Dict:
373
+ def preprocess(self, request: dict, operation) -> dict:
366
374
  """preprocess the event body before validate and action"""
367
375
  return request
368
376
 
369
- def postprocess(self, request: Dict) -> Dict:
377
+ def postprocess(self, request: dict) -> dict:
370
378
  """postprocess, before returning response"""
371
379
  return request
372
380
 
373
- def predict(self, request: Dict) -> Dict:
374
- """model prediction operation"""
381
+ def predict(self, request: dict) -> list:
382
+ """model prediction operation
383
+ :return: list with the model prediction results (can be multi-port) or list of lists for multiple predictions
384
+ """
375
385
  raise NotImplementedError()
376
386
 
377
- def explain(self, request: Dict) -> Dict:
387
+ def explain(self, request: dict) -> dict:
378
388
  """model explain operation"""
379
389
  raise NotImplementedError()
380
390
 
391
+ def _inputs_to_list(self, request: dict) -> dict:
392
+ """
393
+ Convert the inputs from list of dictionary / dictionary to list of lists / list
394
+ where the internal list order is according to the ArtifactModel inputs.
395
+
396
+ :param request: event
397
+ :return: evnet body converting the inputs to be list of lists
398
+ """
399
+ if self.model_spec and self.model_spec.inputs:
400
+ input_order = [feature.name for feature in self.model_spec.inputs]
401
+ else:
402
+ raise mlrun.MLRunInvalidArgumentError(
403
+ "In order to use predict_dict or infer_dict operation you have to provide `model_path` "
404
+ "to the model server and to load it by `load()` function"
405
+ )
406
+ inputs = request.get("inputs")
407
+ try:
408
+ if isinstance(inputs, list) and all(
409
+ isinstance(item, dict) for item in inputs
410
+ ):
411
+ new_inputs = [
412
+ [input_dict[key] for key in input_order] for input_dict in inputs
413
+ ]
414
+ elif isinstance(inputs, dict):
415
+ new_inputs = [inputs[key] for key in input_order]
416
+ else:
417
+ raise mlrun.MLRunInvalidArgumentError(
418
+ "When using predict_dict or infer_dict operation the inputs must be "
419
+ "of type `list[dict]` or `dict`"
420
+ )
421
+ except KeyError:
422
+ raise mlrun.MLRunInvalidArgumentError(
423
+ f"Input dictionary don't contain all the necessary input keys : {input_order}"
424
+ )
425
+ request["inputs"] = new_inputs
426
+ return request
427
+
381
428
 
382
429
  class _ModelLogPusher:
383
430
  def __init__(self, model, context, output_stream=None):
@@ -481,11 +528,17 @@ def _init_endpoint_record(
481
528
  graph_server.function_uri
482
529
  )
483
530
  except Exception as e:
484
- logger.error("Failed to parse function URI", exc=e)
531
+ logger.error("Failed to parse function URI", exc=err_to_str(e))
485
532
  return None
486
533
 
487
534
  # Generating version model value based on the model name and model version
488
- if model.version:
535
+ if model.model_path and model.model_path.startswith("store://"):
536
+ # Enrich the model server with the model artifact metadata
537
+ model.get_model()
538
+ if not model.version:
539
+ # Enrich the model version with the model artifact tag
540
+ model.version = model.model_spec.tag
541
+ model.labels = model.model_spec.labels
489
542
  versioned_model_name = f"{model.name}:{model.version}"
490
543
  else:
491
544
  versioned_model_name = f"{model.name}:latest"
@@ -495,48 +548,74 @@ def _init_endpoint_record(
495
548
  function_uri=graph_server.function_uri, versioned_model=versioned_model_name
496
549
  ).uid
497
550
 
498
- # If model endpoint object was found in DB, skip the creation process.
499
551
  try:
500
- mlrun.get_run_db().get_model_endpoint(project=project, endpoint_id=uid)
501
-
552
+ model_ep = mlrun.get_run_db().get_model_endpoint(
553
+ project=project, endpoint_id=uid
554
+ )
502
555
  except mlrun.errors.MLRunNotFoundError:
556
+ model_ep = None
557
+ except mlrun.errors.MLRunBadRequestError as err:
558
+ logger.info(
559
+ "Cannot get the model endpoints store", err=mlrun.errors.err_to_str(err)
560
+ )
561
+ return
562
+
563
+ if model.context.server.track_models and not model_ep:
503
564
  logger.info("Creating a new model endpoint record", endpoint_id=uid)
565
+ model_endpoint = mlrun.common.schemas.ModelEndpoint(
566
+ metadata=mlrun.common.schemas.ModelEndpointMetadata(
567
+ project=project, labels=model.labels, uid=uid
568
+ ),
569
+ spec=mlrun.common.schemas.ModelEndpointSpec(
570
+ function_uri=graph_server.function_uri,
571
+ model=versioned_model_name,
572
+ model_class=model.__class__.__name__,
573
+ model_uri=model.model_path,
574
+ stream_path=model.context.stream.stream_uri,
575
+ active=True,
576
+ monitoring_mode=mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled,
577
+ ),
578
+ status=mlrun.common.schemas.ModelEndpointStatus(
579
+ endpoint_type=mlrun.common.schemas.model_monitoring.EndpointType.NODE_EP
580
+ ),
581
+ )
504
582
 
505
- try:
506
- model_endpoint = mlrun.common.schemas.ModelEndpoint(
507
- metadata=mlrun.common.schemas.ModelEndpointMetadata(
508
- project=project, labels=model.labels, uid=uid
509
- ),
510
- spec=mlrun.common.schemas.ModelEndpointSpec(
511
- function_uri=graph_server.function_uri,
512
- model=versioned_model_name,
513
- model_class=model.__class__.__name__,
514
- model_uri=model.model_path,
515
- stream_path=config.model_endpoint_monitoring.store_prefixes.default.format(
516
- project=project, kind="stream"
517
- ),
518
- active=True,
519
- monitoring_mode=mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
520
- if model.context.server.track_models
521
- else mlrun.common.schemas.model_monitoring.ModelMonitoringMode.disabled,
522
- ),
523
- status=mlrun.common.schemas.ModelEndpointStatus(
524
- endpoint_type=mlrun.common.schemas.model_monitoring.EndpointType.NODE_EP
525
- ),
526
- )
583
+ db = mlrun.get_run_db()
584
+ db.create_model_endpoint(
585
+ project=project,
586
+ endpoint_id=uid,
587
+ model_endpoint=model_endpoint.dict(),
588
+ )
527
589
 
590
+ elif model_ep:
591
+ attributes = {}
592
+ old_model_uri = model_ep.spec.model_uri
593
+ mlrun.model_monitoring.helpers.enrich_model_endpoint_with_model_uri(
594
+ model_endpoint=model_ep,
595
+ model_obj=model.model_spec,
596
+ )
597
+ if model_ep.spec.model_uri != old_model_uri:
598
+ attributes["model_uri"] = model_ep.spec.model_uri
599
+ if (
600
+ model_ep.spec.monitoring_mode
601
+ == mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
602
+ ) != model.context.server.track_models:
603
+ attributes["monitoring_mode"] = (
604
+ mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
605
+ if model.context.server.track_models
606
+ else mlrun.common.schemas.model_monitoring.ModelMonitoringMode.disabled
607
+ )
608
+ if attributes:
528
609
  db = mlrun.get_run_db()
529
-
530
- db.create_model_endpoint(
610
+ db.patch_model_endpoint(
531
611
  project=project,
532
612
  endpoint_id=uid,
533
- model_endpoint=model_endpoint.dict(),
613
+ attributes=attributes,
614
+ )
615
+ logger.info(
616
+ "Updating model endpoint attributes",
617
+ attributes=attributes,
618
+ endpoint_id=uid,
534
619
  )
535
-
536
- except Exception as e:
537
- logger.error("Failed to create endpoint record", exc=e)
538
-
539
- except Exception as e:
540
- logger.error("Failed to retrieve model endpoint object", exc=e)
541
620
 
542
621
  return uid
mlrun/track/tracker.py CHANGED
@@ -31,8 +31,9 @@ class Tracker(ABC):
31
31
  * Offline: Manually importing models and artifacts into an MLRun project using the `import_x` methods.
32
32
  """
33
33
 
34
+ @staticmethod
34
35
  @abstractmethod
35
- def is_enabled(self) -> bool:
36
+ def is_enabled() -> bool:
36
37
  """
37
38
  Checks if tracker is enabled.
38
39
 
@@ -14,7 +14,7 @@
14
14
 
15
15
  import importlib
16
16
  import inspect
17
- from typing import List, Union
17
+ from typing import Union
18
18
 
19
19
  import mlrun.errors
20
20
  from mlrun.config import config as mlconf
@@ -28,7 +28,7 @@ _TRACKERS = ["mlflow"]
28
28
 
29
29
  # A list for the available trackers during runtime. It will be setup at the beginning of the run by the function
30
30
  # `_collect_available_trackers`:
31
- _AVAILABLE_TRACKERS: List[Tracker] = None
31
+ _AVAILABLE_TRACKERS: list[Tracker] = None
32
32
 
33
33
 
34
34
  class TrackerManager(metaclass=Singleton):
@@ -41,7 +41,7 @@ class TrackerManager(metaclass=Singleton):
41
41
  """
42
42
  Initialize a new empty tracker manager.
43
43
  """
44
- self._trackers: List[Tracker] = []
44
+ self._trackers: list[Tracker] = []
45
45
 
46
46
  # Check general config for tracking usage, if false we return an empty manager
47
47
  if mlconf.external_platform_tracking.enabled:
@@ -15,7 +15,6 @@ import os
15
15
  import pathlib
16
16
  import tempfile
17
17
  import zipfile
18
- from typing import List
19
18
 
20
19
  import mlflow
21
20
  import mlflow.entities
@@ -443,6 +442,11 @@ class MLFlowTracker(Tracker):
443
442
  # Prepare the archive path:
444
443
  model_uri = pathlib.Path(model_uri)
445
444
  archive_path = pathlib.Path(tmp_path) / f"{model_uri.stem}.zip"
445
+ if not os.path.exists(model_uri):
446
+ local_path = mlflow.artifacts.download_artifacts(
447
+ artifact_uri=str(model_uri)
448
+ )
449
+ model_uri = pathlib.Path(local_path)
446
450
 
447
451
  # TODO add progress bar for the case of large files
448
452
  # Zip the artifact:
@@ -526,7 +530,7 @@ class MLFlowTracker(Tracker):
526
530
  )
527
531
 
528
532
  @staticmethod
529
- def _schema_to_feature(schema: mlflow.types.Schema) -> List[Feature]:
533
+ def _schema_to_feature(schema: mlflow.types.Schema) -> list[Feature]:
530
534
  """
531
535
  Cast MLFlow schema to MLRun features.
532
536
 
mlrun/utils/async_http.py CHANGED
@@ -16,7 +16,7 @@
16
16
  import asyncio
17
17
  import logging
18
18
  import typing
19
- from typing import List, Optional
19
+ from typing import Optional
20
20
 
21
21
  import aiohttp
22
22
  import aiohttp.http_exceptions
@@ -38,12 +38,10 @@ class AsyncClientWithRetry(RetryClient):
38
38
  self,
39
39
  max_retries: int = config.http_retry_defaults.max_retries,
40
40
  retry_backoff_factor: float = config.http_retry_defaults.backoff_factor,
41
- retry_on_status_codes: typing.List[
42
- int
43
- ] = config.http_retry_defaults.status_codes,
41
+ retry_on_status_codes: list[int] = config.http_retry_defaults.status_codes,
44
42
  retry_on_exception: bool = True,
45
43
  raise_for_status: bool = True,
46
- blacklisted_methods: typing.Optional[typing.List[str]] = None,
44
+ blacklisted_methods: typing.Optional[list[str]] = None,
47
45
  logger: logging.Logger = None,
48
46
  *args,
49
47
  **kwargs,
@@ -82,7 +80,7 @@ class AsyncClientWithRetry(RetryClient):
82
80
 
83
81
  def _make_requests(
84
82
  self,
85
- params_list: List[RequestParams],
83
+ params_list: list[RequestParams],
86
84
  retry_options: Optional[RetryOptionsBase] = None,
87
85
  raise_for_status: Optional[bool] = None,
88
86
  ) -> "_CustomRequestContext":
@@ -117,7 +115,7 @@ class ExponentialRetryOverride(ExponentialRetry):
117
115
  def __init__(
118
116
  self,
119
117
  retry_on_exception: bool,
120
- blacklisted_methods: typing.List[str],
118
+ blacklisted_methods: list[str],
121
119
  *args,
122
120
  **kwargs,
123
121
  ):
@@ -239,7 +237,7 @@ class _CustomRequestContext(_RequestContext):
239
237
  retry_wait = self._retry_options.get_timeout(
240
238
  attempt=current_attempt, response=None
241
239
  )
242
- self._logger.debug(
240
+ self._logger.warning(
243
241
  "Request failed on retryable exception, retrying",
244
242
  retry_wait_secs=retry_wait,
245
243
  method=params.method,
@@ -63,7 +63,7 @@ class AzureVaultStore:
63
63
  mlconf.secret_stores.azure_vault.secret_path + "/" + file_name
64
64
  )
65
65
  if os.path.isfile(full_path):
66
- with open(full_path, "r") as secret_file:
66
+ with open(full_path) as secret_file:
67
67
  contents = secret_file.read()
68
68
  return contents
69
69
  return None
mlrun/utils/clones.py CHANGED
@@ -18,7 +18,6 @@ import tarfile
18
18
  import tempfile
19
19
  import zipfile
20
20
  from os import path, remove
21
- from typing import Tuple
22
21
  from urllib.parse import urlparse
23
22
 
24
23
  from git import Repo
@@ -91,7 +90,7 @@ def get_repo_url(repo):
91
90
  return url
92
91
 
93
92
 
94
- def add_credentials_git_remote_url(url: str, secrets=None) -> Tuple[str, bool]:
93
+ def add_credentials_git_remote_url(url: str, secrets=None) -> tuple[str, bool]:
95
94
  """Enrich a Git remote URL with credential related secrets, if any are available
96
95
  If no secrets are supplied, or if the secrets are insufficient, the original URL is returned
97
96
  Besides the URL, this function also returns a bool indicating if any enrichment was done
@@ -19,7 +19,7 @@ from mlrun.utils import logger
19
19
 
20
20
 
21
21
  def evaluate_condition_in_separate_process(
22
- condition: str, context: typing.Dict[str, typing.Any], timeout: int = 5
22
+ condition: str, context: dict[str, typing.Any], timeout: int = 5
23
23
  ):
24
24
  if not condition:
25
25
  return True
@@ -44,13 +44,13 @@ def evaluate_condition_in_separate_process(
44
44
 
45
45
 
46
46
  def _evaluate_condition_wrapper(
47
- connection, condition: str, context: typing.Dict[str, typing.Any]
47
+ connection, condition: str, context: dict[str, typing.Any]
48
48
  ):
49
49
  connection.send(_evaluate_condition(condition, context))
50
50
  return connection.close()
51
51
 
52
52
 
53
- def _evaluate_condition(condition: str, context: typing.Dict[str, typing.Any]):
53
+ def _evaluate_condition(condition: str, context: dict[str, typing.Any]):
54
54
  import jinja2.sandbox
55
55
 
56
56
  jinja_env = jinja2.sandbox.SandboxedEnvironment()
mlrun/utils/db.py CHANGED
@@ -12,6 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  #
15
+ import abc
15
16
  import pickle
16
17
  from datetime import datetime
17
18
 
@@ -19,7 +20,7 @@ from sqlalchemy.orm import class_mapper
19
20
 
20
21
 
21
22
  class BaseModel:
22
- def to_dict(self, exclude=None):
23
+ def to_dict(self, exclude=None, strip: bool = False):
23
24
  """
24
25
  NOTE - this function (currently) does not handle serializing relationships
25
26
  """
@@ -28,12 +29,22 @@ class BaseModel:
28
29
  columns = [column.key for column in mapper.columns if column.key not in exclude]
29
30
 
30
31
  def get_key_value(c):
32
+ # all (never say never) DB classes have "object" defined as "full_object"
33
+ if c == "object":
34
+ c = "full_object"
31
35
  if isinstance(getattr(self, c), datetime):
32
36
  return c, getattr(self, c).isoformat()
33
37
  return c, getattr(self, c)
34
38
 
35
39
  return dict(map(get_key_value, columns))
36
40
 
41
+ @abc.abstractmethod
42
+ def get_identifier_string(self):
43
+ """
44
+ This method must be implemented by any subclass.
45
+ """
46
+ pass
47
+
37
48
 
38
49
  class HasStruct(BaseModel):
39
50
  @property
@@ -44,10 +55,17 @@ class HasStruct(BaseModel):
44
55
  def struct(self, value):
45
56
  self.body = pickle.dumps(value)
46
57
 
47
- def to_dict(self, exclude=None):
58
+ def to_dict(self, exclude=None, strip: bool = False):
48
59
  """
49
60
  NOTE - this function (currently) does not handle serializing relationships
50
61
  """
51
62
  exclude = exclude or []
52
63
  exclude.append("body")
53
- return super().to_dict(exclude)
64
+ return super().to_dict(exclude, strip=strip)
65
+
66
+ @abc.abstractmethod
67
+ def get_identifier_string(self):
68
+ """
69
+ This method must be implemented by any subclass.
70
+ """
71
+ pass