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
mlrun/serving/states.py CHANGED
@@ -12,20 +12,31 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- __all__ = ["TaskStep", "RouterStep", "RootFlowStep", "ErrorStep"]
15
+ __all__ = [
16
+ "TaskStep",
17
+ "RouterStep",
18
+ "RootFlowStep",
19
+ "ErrorStep",
20
+ "MonitoringApplicationStep",
21
+ ]
16
22
 
17
23
  import os
18
24
  import pathlib
19
25
  import traceback
20
26
  from copy import copy, deepcopy
21
27
  from inspect import getfullargspec, signature
22
- from typing import Union
28
+ from typing import Any, Union
29
+
30
+ import storey.utils
23
31
 
24
32
  import mlrun
25
33
 
26
34
  from ..config import config
27
35
  from ..datastore import get_stream_pusher
28
- from ..datastore.utils import parse_kafka_url
36
+ from ..datastore.utils import (
37
+ get_kafka_brokers_from_dict,
38
+ parse_kafka_url,
39
+ )
29
40
  from ..errors import MLRunInvalidArgumentError, err_to_str
30
41
  from ..model import ModelObj, ObjectDict
31
42
  from ..platforms.iguazio import parse_path
@@ -52,6 +63,7 @@ class StepKinds:
52
63
  choice = "choice"
53
64
  root = "root"
54
65
  error_step = "error_step"
66
+ monitoring_application = "monitoring_application"
55
67
 
56
68
 
57
69
  _task_step_fields = [
@@ -72,6 +84,9 @@ _task_step_fields = [
72
84
  ]
73
85
 
74
86
 
87
+ MAX_ALLOWED_STEPS = 4500
88
+
89
+
75
90
  def new_model_endpoint(class_name, model_path, handler=None, **class_args):
76
91
  class_args = deepcopy(class_args)
77
92
  class_args["model_path"] = model_path
@@ -324,7 +339,7 @@ class BaseStep(ModelObj):
324
339
  parent = self._parent
325
340
  else:
326
341
  raise GraphError(
327
- f"step {self.name} parent is not set or its not part of a graph"
342
+ f"step {self.name} parent is not set or it's not part of a graph"
328
343
  )
329
344
 
330
345
  name, step = params_to_step(
@@ -346,6 +361,39 @@ class BaseStep(ModelObj):
346
361
  parent._last_added = step
347
362
  return step
348
363
 
364
+ def set_flow(
365
+ self,
366
+ steps: list[Union[str, StepToDict, dict[str, Any]]],
367
+ force: bool = False,
368
+ ):
369
+ """set list of steps as downstream from this step, in the order specified. This will overwrite any existing
370
+ downstream steps.
371
+
372
+ :param steps: list of steps to follow this one
373
+ :param force: whether to overwrite existing downstream steps. If False, this method will fail if any downstream
374
+ steps have already been defined. Defaults to False.
375
+ :return: the last step added to the flow
376
+
377
+ example:
378
+ The below code sets the downstream nodes of step1 by using a list of steps (provided to `set_flow()`) and a
379
+ single step (provided to `to()`), resulting in the graph (step1 -> step2 -> step3 -> step4).
380
+ Notice that using `force=True` is required in case step1 already had downstream nodes (e.g. if the existing
381
+ graph is step1 -> step2_old) and that following the execution of this code the existing downstream steps
382
+ are removed. If the intention is to split the graph (and not to overwrite), please use `to()`.
383
+
384
+ step1.set_flow(
385
+ [
386
+ dict(name="step2", handler="step2_handler"),
387
+ dict(name="step3", class_name="Step3Class"),
388
+ ],
389
+ force=True,
390
+ ).to(dict(name="step4", class_name="Step4Class"))
391
+ """
392
+ raise NotImplementedError("set_flow() can only be called on a FlowStep")
393
+
394
+ def supports_termination(self):
395
+ return False
396
+
349
397
 
350
398
  class TaskStep(BaseStep):
351
399
  """task execution step, runs a class or handler"""
@@ -452,13 +500,15 @@ class TaskStep(BaseStep):
452
500
  class_args[key] = arg
453
501
  class_args.update(extra_kwargs)
454
502
 
455
- # add common args (name, context, ..) only if target class can accept them
456
- argspec = getfullargspec(class_object)
457
- for key in ["name", "context", "input_path", "result_path", "full_event"]:
458
- if argspec.varkw or key in argspec.args:
459
- class_args[key] = getattr(self, key)
460
- if argspec.varkw or "graph_step" in argspec.args:
461
- class_args["graph_step"] = self
503
+ if not isinstance(self, MonitoringApplicationStep):
504
+ # add common args (name, context, ..) only if target class can accept them
505
+ argspec = getfullargspec(class_object)
506
+
507
+ for key in ["name", "context", "input_path", "result_path", "full_event"]:
508
+ if argspec.varkw or key in argspec.args:
509
+ class_args[key] = getattr(self, key)
510
+ if argspec.varkw or "graph_step" in argspec.args:
511
+ class_args["graph_step"] = self
462
512
  return class_args
463
513
 
464
514
  def get_step_class_object(self, namespace):
@@ -549,6 +599,39 @@ class TaskStep(BaseStep):
549
599
  return event
550
600
 
551
601
 
602
+ class MonitoringApplicationStep(TaskStep):
603
+ """monitoring application execution step, runs users class code"""
604
+
605
+ kind = "monitoring_application"
606
+ _default_class = ""
607
+
608
+ def __init__(
609
+ self,
610
+ class_name: Union[str, type] = None,
611
+ class_args: dict = None,
612
+ handler: str = None,
613
+ name: str = None,
614
+ after: list = None,
615
+ full_event: bool = None,
616
+ function: str = None,
617
+ responder: bool = None,
618
+ input_path: str = None,
619
+ result_path: str = None,
620
+ ):
621
+ super().__init__(
622
+ class_name=class_name,
623
+ class_args=class_args,
624
+ handler=handler,
625
+ name=name,
626
+ after=after,
627
+ full_event=full_event,
628
+ function=function,
629
+ responder=responder,
630
+ input_path=input_path,
631
+ result_path=result_path,
632
+ )
633
+
634
+
552
635
  class ErrorStep(TaskStep):
553
636
  """error execution step, runs a class or handler"""
554
637
 
@@ -556,6 +639,34 @@ class ErrorStep(TaskStep):
556
639
  _dict_fields = _task_step_fields + ["before", "base_step"]
557
640
  _default_class = ""
558
641
 
642
+ def __init__(
643
+ self,
644
+ class_name: Union[str, type] = None,
645
+ class_args: dict = None,
646
+ handler: str = None,
647
+ name: str = None,
648
+ after: list = None,
649
+ full_event: bool = None,
650
+ function: str = None,
651
+ responder: bool = None,
652
+ input_path: str = None,
653
+ result_path: str = None,
654
+ ):
655
+ super().__init__(
656
+ class_name=class_name,
657
+ class_args=class_args,
658
+ handler=handler,
659
+ name=name,
660
+ after=after,
661
+ full_event=full_event,
662
+ function=function,
663
+ responder=responder,
664
+ input_path=input_path,
665
+ result_path=result_path,
666
+ )
667
+ self.before = None
668
+ self.base_step = None
669
+
559
670
 
560
671
  class RouterStep(TaskStep):
561
672
  """router step, implement routing logic for running child routes"""
@@ -625,6 +736,11 @@ class RouterStep(TaskStep):
625
736
  if not route:
626
737
  route = TaskStep(class_name, class_args, handler=handler)
627
738
  route.function = function or route.function
739
+
740
+ if len(self._routes) >= MAX_ALLOWED_STEPS:
741
+ raise mlrun.errors.MLRunInvalidArgumentError(
742
+ f"Cannot create the serving graph: the maximum number of steps is {MAX_ALLOWED_STEPS}"
743
+ )
628
744
  route = self._routes.update(key, route)
629
745
  route.set_parent(self)
630
746
  return route
@@ -729,13 +845,45 @@ class QueueStep(BaseStep):
729
845
  def async_object(self):
730
846
  return self._async_object
731
847
 
848
+ def to(
849
+ self,
850
+ class_name: Union[str, StepToDict] = None,
851
+ name: str = None,
852
+ handler: str = None,
853
+ graph_shape: str = None,
854
+ function: str = None,
855
+ full_event: bool = None,
856
+ input_path: str = None,
857
+ result_path: str = None,
858
+ **class_args,
859
+ ):
860
+ if not function:
861
+ name = get_name(name, class_name)
862
+ raise mlrun.errors.MLRunInvalidArgumentError(
863
+ f"step '{name}' must specify a function, because it follows a queue step"
864
+ )
865
+ return super().to(
866
+ class_name,
867
+ name,
868
+ handler,
869
+ graph_shape,
870
+ function,
871
+ full_event,
872
+ input_path,
873
+ result_path,
874
+ **class_args,
875
+ )
876
+
732
877
  def run(self, event, *args, **kwargs):
733
878
  data = event.body
734
879
  if not data:
735
880
  return event
736
881
 
737
882
  if self._stream:
738
- self._stream.push({"id": event.id, "body": data, "path": event.path})
883
+ full_event = self.options.get("full_event")
884
+ if full_event or full_event is None and self.next:
885
+ data = storey.utils.wrap_event_for_serialization(event, data)
886
+ self._stream.push(data)
739
887
  event.terminated = True
740
888
  event.body = None
741
889
  return event
@@ -1132,23 +1280,17 @@ class FlowStep(BaseStep):
1132
1280
  if self._controller:
1133
1281
  # async flow (using storey)
1134
1282
  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()
1283
+ resp = self._controller.emit(
1284
+ event, return_awaitable_result=self._wait_for_result
1285
+ )
1286
+ if self._wait_for_result and resp:
1287
+ return resp.await_result()
1148
1288
  event = copy(event)
1149
1289
  event.body = {"id": event.id}
1150
1290
  return event
1151
1291
 
1292
+ event = storey.utils.unpack_event_if_wrapped(event)
1293
+
1152
1294
  if len(self._start_steps) == 0:
1153
1295
  return event
1154
1296
  next_obj = self._start_steps[0]
@@ -1182,6 +1324,7 @@ class FlowStep(BaseStep):
1182
1324
 
1183
1325
  def wait_for_completion(self):
1184
1326
  """wait for completion of run in async flows"""
1327
+
1185
1328
  if self._controller:
1186
1329
  if hasattr(self._controller, "terminate"):
1187
1330
  self._controller.terminate()
@@ -1234,6 +1377,30 @@ class FlowStep(BaseStep):
1234
1377
  )
1235
1378
  self[step_name].after_step(name)
1236
1379
 
1380
+ def set_flow(
1381
+ self,
1382
+ steps: list[Union[str, StepToDict, dict[str, Any]]],
1383
+ force: bool = False,
1384
+ ):
1385
+ if not force and self.steps:
1386
+ raise mlrun.errors.MLRunInvalidArgumentError(
1387
+ "set_flow() called on a step that already has downstream steps. "
1388
+ "If you want to overwrite existing steps, set force=True."
1389
+ )
1390
+
1391
+ self.steps = None
1392
+ step = self
1393
+ for next_step in steps:
1394
+ if isinstance(next_step, dict):
1395
+ step = step.to(**next_step)
1396
+ else:
1397
+ step = step.to(next_step)
1398
+
1399
+ return step
1400
+
1401
+ def supports_termination(self):
1402
+ return self.engine != "sync"
1403
+
1237
1404
 
1238
1405
  class RootFlowStep(FlowStep):
1239
1406
  """root flow step"""
@@ -1248,6 +1415,7 @@ classes_map = {
1248
1415
  "flow": FlowStep,
1249
1416
  "queue": QueueStep,
1250
1417
  "error_step": ErrorStep,
1418
+ "monitoring_application": MonitoringApplicationStep,
1251
1419
  }
1252
1420
 
1253
1421
 
@@ -1471,15 +1639,17 @@ def _init_async_objects(context, steps):
1471
1639
  if step.path and not skip_stream:
1472
1640
  stream_path = step.path
1473
1641
  endpoint = None
1474
- options = {}
1642
+ # in case of a queue, we default to a full_event=True
1643
+ full_event = step.options.get("full_event")
1644
+ options = {
1645
+ "full_event": full_event or full_event is None and step.next
1646
+ }
1475
1647
  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
- )
1648
+
1649
+ kafka_brokers = get_kafka_brokers_from_dict(options, pop=True)
1650
+
1651
+ if stream_path.startswith("kafka://") or kafka_brokers:
1652
+ topic, brokers = parse_kafka_url(stream_path, kafka_brokers)
1483
1653
 
1484
1654
  kafka_producer_options = options.pop(
1485
1655
  "kafka_producer_options", None
@@ -1487,7 +1657,7 @@ def _init_async_objects(context, steps):
1487
1657
 
1488
1658
  step._async_object = storey.KafkaTarget(
1489
1659
  topic=topic,
1490
- bootstrap_servers=bootstrap_servers,
1660
+ brokers=brokers,
1491
1661
  producer_options=kafka_producer_options,
1492
1662
  context=context,
1493
1663
  **options,
@@ -1514,6 +1684,7 @@ def _init_async_objects(context, steps):
1514
1684
  result_path=step.result_path,
1515
1685
  name=step.name,
1516
1686
  context=context,
1687
+ pass_context=step._inject_context,
1517
1688
  )
1518
1689
  if (
1519
1690
  respond_supported
@@ -1526,9 +1697,11 @@ def _init_async_objects(context, steps):
1526
1697
  wait_for_result = True
1527
1698
 
1528
1699
  source_args = context.get_param("source_args", {})
1700
+ explicit_ack = (
1701
+ is_explicit_ack_supported(context) and mlrun.mlconf.is_explicit_ack_enabled()
1702
+ )
1529
1703
 
1530
- explicit_ack = is_explicit_ack_supported(context) and mlrun.mlconf.is_explicit_ack()
1531
-
1704
+ # TODO: Change to AsyncEmitSource once we can drop support for nuclio<1.12.10
1532
1705
  default_source = storey.SyncEmitSource(
1533
1706
  context=context,
1534
1707
  explicit_ack=explicit_ack,
mlrun/serving/utils.py CHANGED
@@ -46,7 +46,16 @@ 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
+ meta_keys = [
50
+ "context",
51
+ "name",
52
+ "input_path",
53
+ "result_path",
54
+ "full_event",
55
+ "kwargs",
56
+ ]
57
+
58
+ def to_dict(self, fields: list = None, exclude: list = None, strip: bool = False):
50
59
  """convert the step object to a python dictionary"""
51
60
  fields = fields or getattr(self, "_dict_fields", None)
52
61
  if not fields:
@@ -54,24 +63,16 @@ class StepToDict:
54
63
  if exclude:
55
64
  fields = [field for field in fields if field not in exclude]
56
65
 
57
- meta_keys = [
58
- "context",
59
- "name",
60
- "input_path",
61
- "result_path",
62
- "full_event",
63
- "kwargs",
64
- ]
65
66
  args = {
66
67
  key: getattr(self, key)
67
68
  for key in fields
68
- if getattr(self, key, None) is not None and key not in meta_keys
69
+ if getattr(self, key, None) is not None and key not in self.meta_keys
69
70
  }
70
71
  # add storey kwargs or extra kwargs
71
72
  if "kwargs" in fields and (hasattr(self, "kwargs") or hasattr(self, "_kwargs")):
72
73
  kwargs = getattr(self, "kwargs", {}) or getattr(self, "_kwargs", {})
73
74
  for key, value in kwargs.items():
74
- if key not in meta_keys:
75
+ if key not in self.meta_keys:
75
76
  args[key] = value
76
77
 
77
78
  mod_name = self.__class__.__module__
@@ -80,7 +81,9 @@ class StepToDict:
80
81
  class_path = f"{mod_name}.{class_path}"
81
82
  struct = {
82
83
  "class_name": class_path,
83
- "name": self.name or self.__class__.__name__,
84
+ "name": self.name
85
+ if hasattr(self, "name") and self.name
86
+ else self.__class__.__name__,
84
87
  "class_args": args,
85
88
  }
86
89
  if hasattr(self, "_STEP_KIND"):
@@ -94,8 +97,13 @@ class StepToDict:
94
97
  return struct
95
98
 
96
99
 
100
+ class MonitoringApplicationToDict(StepToDict):
101
+ _STEP_KIND = "monitoring_application"
102
+ meta_keys = []
103
+
104
+
97
105
  class RouterToDict(StepToDict):
98
106
  _STEP_KIND = "router"
99
107
 
100
- def to_dict(self, fields=None, exclude=None):
101
- return super().to_dict(exclude=["routes"])
108
+ def to_dict(self, fields: list = None, exclude: list = None, strip: bool = False):
109
+ 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