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/serving/states.py CHANGED
@@ -19,13 +19,16 @@ import pathlib
19
19
  import traceback
20
20
  from copy import copy, deepcopy
21
21
  from inspect import getfullargspec, signature
22
- from typing import Union
22
+ from typing import Any, Union
23
23
 
24
24
  import mlrun
25
25
 
26
26
  from ..config import config
27
27
  from ..datastore import get_stream_pusher
28
- from ..datastore.utils import parse_kafka_url
28
+ from ..datastore.utils import (
29
+ get_kafka_brokers_from_dict,
30
+ parse_kafka_url,
31
+ )
29
32
  from ..errors import MLRunInvalidArgumentError, err_to_str
30
33
  from ..model import ModelObj, ObjectDict
31
34
  from ..platforms.iguazio import parse_path
@@ -324,7 +327,7 @@ class BaseStep(ModelObj):
324
327
  parent = self._parent
325
328
  else:
326
329
  raise GraphError(
327
- f"step {self.name} parent is not set or its not part of a graph"
330
+ f"step {self.name} parent is not set or it's not part of a graph"
328
331
  )
329
332
 
330
333
  name, step = params_to_step(
@@ -346,6 +349,36 @@ class BaseStep(ModelObj):
346
349
  parent._last_added = step
347
350
  return step
348
351
 
352
+ def set_flow(
353
+ self,
354
+ steps: list[Union[str, StepToDict, dict[str, Any]]],
355
+ force: bool = False,
356
+ ):
357
+ """set list of steps as downstream from this step, in the order specified. This will overwrite any existing
358
+ downstream steps.
359
+
360
+ :param steps: list of steps to follow this one
361
+ :param force: whether to overwrite existing downstream steps. If False, this method will fail if any downstream
362
+ steps have already been defined. Defaults to False.
363
+ :return: the last step added to the flow
364
+
365
+ example:
366
+ The below code sets the downstream nodes of step1 by using a list of steps (provided to `set_flow()`) and a
367
+ single step (provided to `to()`), resulting in the graph (step1 -> step2 -> step3 -> step4).
368
+ Notice that using `force=True` is required in case step1 already had downstream nodes (e.g. if the existing
369
+ graph is step1 -> step2_old) and that following the execution of this code the existing downstream steps
370
+ are removed. If the intention is to split the graph (and not to overwrite), please use `to()`.
371
+
372
+ step1.set_flow(
373
+ [
374
+ dict(name="step2", handler="step2_handler"),
375
+ dict(name="step3", class_name="Step3Class"),
376
+ ],
377
+ force=True,
378
+ ).to(dict(name="step4", class_name="Step4Class"))
379
+ """
380
+ raise NotImplementedError("set_flow() can only be called on a FlowStep")
381
+
349
382
 
350
383
  class TaskStep(BaseStep):
351
384
  """task execution step, runs a class or handler"""
@@ -556,6 +589,34 @@ class ErrorStep(TaskStep):
556
589
  _dict_fields = _task_step_fields + ["before", "base_step"]
557
590
  _default_class = ""
558
591
 
592
+ def __init__(
593
+ self,
594
+ class_name: Union[str, type] = None,
595
+ class_args: dict = None,
596
+ handler: str = None,
597
+ name: str = None,
598
+ after: list = None,
599
+ full_event: bool = None,
600
+ function: str = None,
601
+ responder: bool = None,
602
+ input_path: str = None,
603
+ result_path: str = None,
604
+ ):
605
+ super().__init__(
606
+ class_name=class_name,
607
+ class_args=class_args,
608
+ handler=handler,
609
+ name=name,
610
+ after=after,
611
+ full_event=full_event,
612
+ function=function,
613
+ responder=responder,
614
+ input_path=input_path,
615
+ result_path=result_path,
616
+ )
617
+ self.before = None
618
+ self.base_step = None
619
+
559
620
 
560
621
  class RouterStep(TaskStep):
561
622
  """router step, implement routing logic for running child routes"""
@@ -1132,19 +1193,11 @@ class FlowStep(BaseStep):
1132
1193
  if self._controller:
1133
1194
  # async flow (using storey)
1134
1195
  event._awaitable_result = None
1135
- if config.datastore.async_source_mode == "enabled":
1136
- resp_awaitable = self._controller.emit(
1137
- event, await_result=self._wait_for_result
1138
- )
1139
- if self._wait_for_result:
1140
- return resp_awaitable
1141
- return self._await_and_return_id(resp_awaitable, event)
1142
- else:
1143
- resp = self._controller.emit(
1144
- event, return_awaitable_result=self._wait_for_result
1145
- )
1146
- if self._wait_for_result and resp:
1147
- return resp.await_result()
1196
+ resp = self._controller.emit(
1197
+ event, return_awaitable_result=self._wait_for_result
1198
+ )
1199
+ if self._wait_for_result and resp:
1200
+ return resp.await_result()
1148
1201
  event = copy(event)
1149
1202
  event.body = {"id": event.id}
1150
1203
  return event
@@ -1182,6 +1235,7 @@ class FlowStep(BaseStep):
1182
1235
 
1183
1236
  def wait_for_completion(self):
1184
1237
  """wait for completion of run in async flows"""
1238
+
1185
1239
  if self._controller:
1186
1240
  if hasattr(self._controller, "terminate"):
1187
1241
  self._controller.terminate()
@@ -1234,6 +1288,27 @@ class FlowStep(BaseStep):
1234
1288
  )
1235
1289
  self[step_name].after_step(name)
1236
1290
 
1291
+ def set_flow(
1292
+ self,
1293
+ steps: list[Union[str, StepToDict, dict[str, Any]]],
1294
+ force: bool = False,
1295
+ ):
1296
+ if not force and self.steps:
1297
+ raise mlrun.errors.MLRunInvalidArgumentError(
1298
+ "set_flow() called on a step that already has downstream steps. "
1299
+ "If you want to overwrite existing steps, set force=True."
1300
+ )
1301
+
1302
+ self.steps = None
1303
+ step = self
1304
+ for next_step in steps:
1305
+ if isinstance(next_step, dict):
1306
+ step = step.to(**next_step)
1307
+ else:
1308
+ step = step.to(next_step)
1309
+
1310
+ return step
1311
+
1237
1312
 
1238
1313
  class RootFlowStep(FlowStep):
1239
1314
  """root flow step"""
@@ -1473,13 +1548,11 @@ def _init_async_objects(context, steps):
1473
1548
  endpoint = None
1474
1549
  options = {}
1475
1550
  options.update(step.options)
1476
- kafka_bootstrap_servers = options.pop(
1477
- "kafka_bootstrap_servers", None
1478
- )
1479
- if stream_path.startswith("kafka://") or kafka_bootstrap_servers:
1480
- topic, bootstrap_servers = parse_kafka_url(
1481
- stream_path, kafka_bootstrap_servers
1482
- )
1551
+
1552
+ kafka_brokers = get_kafka_brokers_from_dict(options, pop=True)
1553
+
1554
+ if stream_path.startswith("kafka://") or kafka_brokers:
1555
+ topic, brokers = parse_kafka_url(stream_path, kafka_brokers)
1483
1556
 
1484
1557
  kafka_producer_options = options.pop(
1485
1558
  "kafka_producer_options", None
@@ -1487,7 +1560,7 @@ def _init_async_objects(context, steps):
1487
1560
 
1488
1561
  step._async_object = storey.KafkaTarget(
1489
1562
  topic=topic,
1490
- bootstrap_servers=bootstrap_servers,
1563
+ brokers=brokers,
1491
1564
  producer_options=kafka_producer_options,
1492
1565
  context=context,
1493
1566
  **options,
@@ -1514,6 +1587,7 @@ def _init_async_objects(context, steps):
1514
1587
  result_path=step.result_path,
1515
1588
  name=step.name,
1516
1589
  context=context,
1590
+ pass_context=step._inject_context,
1517
1591
  )
1518
1592
  if (
1519
1593
  respond_supported
@@ -1526,9 +1600,9 @@ def _init_async_objects(context, steps):
1526
1600
  wait_for_result = True
1527
1601
 
1528
1602
  source_args = context.get_param("source_args", {})
1529
-
1530
1603
  explicit_ack = is_explicit_ack_supported(context) and mlrun.mlconf.is_explicit_ack()
1531
1604
 
1605
+ # TODO: Change to AsyncEmitSource once we can drop support for nuclio<1.12.10
1532
1606
  default_source = storey.SyncEmitSource(
1533
1607
  context=context,
1534
1608
  explicit_ack=explicit_ack,
mlrun/serving/utils.py CHANGED
@@ -46,7 +46,7 @@ def _update_result_body(result_path, event_body, result):
46
46
  class StepToDict:
47
47
  """auto serialization of graph steps to a python dictionary"""
48
48
 
49
- def to_dict(self, fields=None, exclude=None):
49
+ def to_dict(self, fields: list = None, exclude: list = None, strip: bool = False):
50
50
  """convert the step object to a python dictionary"""
51
51
  fields = fields or getattr(self, "_dict_fields", None)
52
52
  if not fields:
@@ -97,5 +97,5 @@ class StepToDict:
97
97
  class RouterToDict(StepToDict):
98
98
  _STEP_KIND = "router"
99
99
 
100
- def to_dict(self, fields=None, exclude=None):
101
- return super().to_dict(exclude=["routes"])
100
+ def to_dict(self, fields: list = None, exclude: list = None, strip: bool = False):
101
+ return super().to_dict(exclude=["routes"], strip=strip)
@@ -18,7 +18,6 @@ import socket
18
18
  from copy import deepcopy
19
19
  from datetime import datetime
20
20
  from io import BytesIO
21
- from typing import Dict
22
21
  from urllib.request import urlopen
23
22
 
24
23
  import nuclio
@@ -26,7 +25,7 @@ import nuclio
26
25
  import mlrun
27
26
  from mlrun.errors import err_to_str
28
27
  from mlrun.platforms.iguazio import OutputStream
29
- from mlrun.runtimes import RemoteRuntime
28
+ from mlrun.runtimes.nuclio.function import RemoteRuntime
30
29
 
31
30
  serving_handler = "handler"
32
31
 
@@ -97,16 +96,16 @@ class MLModelServer:
97
96
  if not self.ready and not self.model:
98
97
  raise ValueError("please specify a load method or a model object")
99
98
 
100
- def preprocess(self, request: Dict) -> Dict:
99
+ def preprocess(self, request: dict) -> dict:
101
100
  return request
102
101
 
103
- def postprocess(self, request: Dict) -> Dict:
102
+ def postprocess(self, request: dict) -> dict:
104
103
  return request
105
104
 
106
- def predict(self, request: Dict) -> Dict:
105
+ def predict(self, request: dict) -> dict:
107
106
  raise NotImplementedError()
108
107
 
109
- def explain(self, request: Dict) -> Dict:
108
+ def explain(self, request: dict) -> dict:
110
109
  raise NotImplementedError()
111
110
 
112
111
 
@@ -200,7 +199,7 @@ class _ServerInfo:
200
199
  class HTTPHandler:
201
200
  kind = ""
202
201
 
203
- def __init__(self, models: Dict, server: _ServerInfo = None):
202
+ def __init__(self, models: dict, server: _ServerInfo = None):
204
203
  self.models = models
205
204
  self.srvinfo = server
206
205
  self.context = None
@@ -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 Union
19
19
 
20
20
  import mlrun.common.model_monitoring
21
21
  import mlrun.common.schemas.model_monitoring
22
22
  from mlrun.artifacts import ModelArtifact # noqa: F401
23
23
  from mlrun.config import config
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()}
@@ -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:
@@ -362,22 +368,59 @@ class V2ModelServer(StepToDict):
362
368
 
363
369
  return request
364
370
 
365
- def preprocess(self, request: Dict, operation) -> Dict:
371
+ def preprocess(self, request: dict, operation) -> dict:
366
372
  """preprocess the event body before validate and action"""
367
373
  return request
368
374
 
369
- def postprocess(self, request: Dict) -> Dict:
375
+ def postprocess(self, request: dict) -> dict:
370
376
  """postprocess, before returning response"""
371
377
  return request
372
378
 
373
- def predict(self, request: Dict) -> Dict:
379
+ def predict(self, request: dict) -> dict:
374
380
  """model prediction operation"""
375
381
  raise NotImplementedError()
376
382
 
377
- def explain(self, request: Dict) -> Dict:
383
+ def explain(self, request: dict) -> dict:
378
384
  """model explain operation"""
379
385
  raise NotImplementedError()
380
386
 
387
+ def _inputs_to_list(self, request: dict) -> dict:
388
+ """
389
+ Convert the inputs from list of dictionary / dictionary to list of lists / list
390
+ where the internal list order is according to the ArtifactModel inputs.
391
+
392
+ :param request: event
393
+ :return: evnet body converting the inputs to be list of lists
394
+ """
395
+ if self.model_spec and self.model_spec.inputs:
396
+ input_order = [feature.name for feature in self.model_spec.inputs]
397
+ else:
398
+ raise mlrun.MLRunInvalidArgumentError(
399
+ "In order to use predict_dict or infer_dict operation you have to provide `model_path` "
400
+ "to the model server and to load it by `load()` function"
401
+ )
402
+ inputs = request.get("inputs")
403
+ try:
404
+ if isinstance(inputs, list) and all(
405
+ isinstance(item, dict) for item in inputs
406
+ ):
407
+ new_inputs = [
408
+ [input_dict[key] for key in input_order] for input_dict in inputs
409
+ ]
410
+ elif isinstance(inputs, dict):
411
+ new_inputs = [inputs[key] for key in input_order]
412
+ else:
413
+ raise mlrun.MLRunInvalidArgumentError(
414
+ "When using predict_dict or infer_dict operation the inputs must be "
415
+ "of type `list[dict]` or `dict`"
416
+ )
417
+ except KeyError:
418
+ raise mlrun.MLRunInvalidArgumentError(
419
+ f"Input dictionary don't contain all the necessary input keys : {input_order}"
420
+ )
421
+ request["inputs"] = new_inputs
422
+ return request
423
+
381
424
 
382
425
  class _ModelLogPusher:
383
426
  def __init__(self, model, context, output_stream=None):
@@ -481,15 +524,11 @@ def _init_endpoint_record(
481
524
  graph_server.function_uri
482
525
  )
483
526
  except Exception as e:
484
- logger.error("Failed to parse function URI", exc=e)
527
+ logger.error("Failed to parse function URI", exc=err_to_str(e))
485
528
  return None
486
529
 
487
530
  # Generating version model value based on the model name and model version
488
- if model.model_path and model.model_path.startswith("store://"):
489
- # Enrich the model server with the model artifact metadata
490
- model.get_model()
491
- model.version = model.model_spec.tag
492
- model.labels = model.model_spec.labels
531
+ if model.version:
493
532
  versioned_model_name = f"{model.name}:{model.version}"
494
533
  else:
495
534
  versioned_model_name = f"{model.name}:latest"
@@ -538,9 +577,9 @@ def _init_endpoint_record(
538
577
  )
539
578
 
540
579
  except Exception as e:
541
- logger.error("Failed to create endpoint record", exc=e)
580
+ logger.error("Failed to create endpoint record", exc=err_to_str(e))
542
581
 
543
582
  except Exception as e:
544
- logger.error("Failed to retrieve model endpoint object", exc=e)
583
+ logger.error("Failed to retrieve model endpoint object", exc=err_to_str(e))
545
584
 
546
585
  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
@@ -526,7 +525,7 @@ class MLFlowTracker(Tracker):
526
525
  )
527
526
 
528
527
  @staticmethod
529
- def _schema_to_feature(schema: mlflow.types.Schema) -> List[Feature]:
528
+ def _schema_to_feature(schema: mlflow.types.Schema) -> list[Feature]:
530
529
  """
531
530
  Cast MLFlow schema to MLRun features.
532
531
 
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
  ):
@@ -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
@@ -19,7 +19,7 @@ from sqlalchemy.orm import class_mapper
19
19
 
20
20
 
21
21
  class BaseModel:
22
- def to_dict(self, exclude=None):
22
+ def to_dict(self, exclude=None, strip: bool = False):
23
23
  """
24
24
  NOTE - this function (currently) does not handle serializing relationships
25
25
  """
@@ -44,10 +44,10 @@ class HasStruct(BaseModel):
44
44
  def struct(self, value):
45
45
  self.body = pickle.dumps(value)
46
46
 
47
- def to_dict(self, exclude=None):
47
+ def to_dict(self, exclude=None, strip: bool = False):
48
48
  """
49
49
  NOTE - this function (currently) does not handle serializing relationships
50
50
  """
51
51
  exclude = exclude or []
52
52
  exclude.append("body")
53
- return super().to_dict(exclude)
53
+ return super().to_dict(exclude, strip=strip)