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.
- mlrun/__init__.py +11 -1
- mlrun/__main__.py +26 -112
- mlrun/alerts/__init__.py +15 -0
- mlrun/alerts/alert.py +144 -0
- mlrun/api/schemas/__init__.py +5 -4
- mlrun/artifacts/__init__.py +8 -3
- mlrun/artifacts/base.py +46 -257
- mlrun/artifacts/dataset.py +11 -192
- mlrun/artifacts/manager.py +47 -48
- mlrun/artifacts/model.py +31 -159
- mlrun/artifacts/plots.py +23 -380
- mlrun/common/constants.py +69 -0
- mlrun/common/db/sql_session.py +2 -3
- mlrun/common/formatters/__init__.py +19 -0
- mlrun/common/formatters/artifact.py +21 -0
- mlrun/common/formatters/base.py +78 -0
- mlrun/common/formatters/function.py +41 -0
- mlrun/common/formatters/pipeline.py +53 -0
- mlrun/common/formatters/project.py +51 -0
- mlrun/common/helpers.py +1 -2
- mlrun/common/model_monitoring/helpers.py +9 -5
- mlrun/{runtimes → common/runtimes}/constants.py +37 -9
- mlrun/common/schemas/__init__.py +24 -4
- mlrun/common/schemas/alert.py +203 -0
- mlrun/common/schemas/api_gateway.py +148 -0
- mlrun/common/schemas/artifact.py +18 -8
- mlrun/common/schemas/auth.py +11 -5
- mlrun/common/schemas/background_task.py +1 -1
- mlrun/common/schemas/client_spec.py +4 -1
- mlrun/common/schemas/feature_store.py +16 -16
- mlrun/common/schemas/frontend_spec.py +8 -7
- mlrun/common/schemas/function.py +5 -1
- mlrun/common/schemas/hub.py +11 -18
- mlrun/common/schemas/memory_reports.py +2 -2
- mlrun/common/schemas/model_monitoring/__init__.py +18 -3
- mlrun/common/schemas/model_monitoring/constants.py +83 -26
- mlrun/common/schemas/model_monitoring/grafana.py +13 -9
- mlrun/common/schemas/model_monitoring/model_endpoints.py +99 -16
- mlrun/common/schemas/notification.py +4 -4
- mlrun/common/schemas/object.py +2 -2
- mlrun/{runtimes/mpijob/v1alpha1.py → common/schemas/pagination.py} +10 -13
- mlrun/common/schemas/pipeline.py +1 -10
- mlrun/common/schemas/project.py +24 -23
- mlrun/common/schemas/runtime_resource.py +8 -12
- mlrun/common/schemas/schedule.py +3 -3
- mlrun/common/schemas/tag.py +1 -2
- mlrun/common/schemas/workflow.py +2 -2
- mlrun/common/types.py +7 -1
- mlrun/config.py +54 -17
- mlrun/data_types/to_pandas.py +10 -12
- mlrun/datastore/__init__.py +5 -8
- mlrun/datastore/alibaba_oss.py +130 -0
- mlrun/datastore/azure_blob.py +17 -5
- mlrun/datastore/base.py +62 -39
- mlrun/datastore/datastore.py +28 -9
- mlrun/datastore/datastore_profile.py +146 -20
- mlrun/datastore/filestore.py +0 -1
- mlrun/datastore/google_cloud_storage.py +6 -2
- mlrun/datastore/hdfs.py +56 -0
- mlrun/datastore/inmem.py +2 -2
- mlrun/datastore/redis.py +6 -2
- mlrun/datastore/s3.py +9 -0
- mlrun/datastore/snowflake_utils.py +43 -0
- mlrun/datastore/sources.py +201 -96
- mlrun/datastore/spark_utils.py +1 -2
- mlrun/datastore/store_resources.py +7 -7
- mlrun/datastore/targets.py +358 -104
- mlrun/datastore/utils.py +72 -58
- mlrun/datastore/v3io.py +5 -1
- mlrun/db/base.py +185 -35
- mlrun/db/factory.py +1 -1
- mlrun/db/httpdb.py +614 -179
- mlrun/db/nopdb.py +210 -26
- mlrun/errors.py +12 -1
- mlrun/execution.py +41 -24
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +40 -72
- mlrun/feature_store/common.py +1 -1
- mlrun/feature_store/feature_set.py +76 -55
- mlrun/feature_store/feature_vector.py +28 -30
- mlrun/feature_store/ingestion.py +7 -6
- mlrun/feature_store/retrieval/base.py +16 -11
- mlrun/feature_store/retrieval/conversion.py +11 -13
- mlrun/feature_store/retrieval/dask_merger.py +2 -0
- mlrun/feature_store/retrieval/job.py +9 -3
- mlrun/feature_store/retrieval/local_merger.py +2 -0
- mlrun/feature_store/retrieval/spark_merger.py +34 -24
- mlrun/feature_store/steps.py +37 -34
- mlrun/features.py +9 -20
- mlrun/frameworks/_common/artifacts_library.py +9 -9
- mlrun/frameworks/_common/mlrun_interface.py +5 -5
- mlrun/frameworks/_common/model_handler.py +48 -48
- mlrun/frameworks/_common/plan.py +2 -3
- mlrun/frameworks/_common/producer.py +3 -4
- mlrun/frameworks/_common/utils.py +5 -5
- mlrun/frameworks/_dl_common/loggers/logger.py +6 -7
- mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +9 -9
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +23 -47
- mlrun/frameworks/_ml_common/artifacts_library.py +1 -2
- mlrun/frameworks/_ml_common/loggers/logger.py +3 -4
- mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +4 -5
- mlrun/frameworks/_ml_common/model_handler.py +24 -24
- mlrun/frameworks/_ml_common/pkl_model_server.py +2 -2
- mlrun/frameworks/_ml_common/plan.py +1 -1
- mlrun/frameworks/_ml_common/plans/calibration_curve_plan.py +2 -3
- mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +2 -3
- mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
- mlrun/frameworks/_ml_common/plans/feature_importance_plan.py +3 -3
- mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
- mlrun/frameworks/_ml_common/utils.py +4 -4
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +9 -9
- mlrun/frameworks/huggingface/model_server.py +4 -4
- mlrun/frameworks/lgbm/__init__.py +33 -33
- mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
- mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -5
- mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -5
- mlrun/frameworks/lgbm/mlrun_interfaces/booster_mlrun_interface.py +1 -3
- mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +6 -6
- mlrun/frameworks/lgbm/model_handler.py +10 -10
- mlrun/frameworks/lgbm/model_server.py +6 -6
- mlrun/frameworks/lgbm/utils.py +5 -5
- mlrun/frameworks/onnx/dataset.py +8 -8
- mlrun/frameworks/onnx/mlrun_interface.py +3 -3
- mlrun/frameworks/onnx/model_handler.py +6 -6
- mlrun/frameworks/onnx/model_server.py +7 -7
- mlrun/frameworks/parallel_coordinates.py +4 -3
- mlrun/frameworks/pytorch/__init__.py +18 -18
- mlrun/frameworks/pytorch/callbacks/callback.py +4 -5
- mlrun/frameworks/pytorch/callbacks/logging_callback.py +17 -17
- mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +11 -11
- mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +23 -29
- mlrun/frameworks/pytorch/callbacks_handler.py +38 -38
- mlrun/frameworks/pytorch/mlrun_interface.py +20 -20
- mlrun/frameworks/pytorch/model_handler.py +17 -17
- mlrun/frameworks/pytorch/model_server.py +7 -7
- mlrun/frameworks/sklearn/__init__.py +13 -13
- mlrun/frameworks/sklearn/estimator.py +4 -4
- mlrun/frameworks/sklearn/metrics_library.py +14 -14
- mlrun/frameworks/sklearn/mlrun_interface.py +3 -6
- mlrun/frameworks/sklearn/model_handler.py +2 -2
- mlrun/frameworks/tf_keras/__init__.py +10 -7
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +15 -15
- mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +11 -11
- mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +19 -23
- mlrun/frameworks/tf_keras/mlrun_interface.py +9 -11
- mlrun/frameworks/tf_keras/model_handler.py +14 -14
- mlrun/frameworks/tf_keras/model_server.py +6 -6
- mlrun/frameworks/xgboost/__init__.py +13 -13
- mlrun/frameworks/xgboost/model_handler.py +6 -6
- mlrun/k8s_utils.py +14 -16
- mlrun/launcher/__init__.py +1 -1
- mlrun/launcher/base.py +16 -15
- mlrun/launcher/client.py +8 -6
- mlrun/launcher/factory.py +1 -1
- mlrun/launcher/local.py +17 -11
- mlrun/launcher/remote.py +16 -10
- mlrun/lists.py +7 -6
- mlrun/model.py +238 -73
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/api.py +138 -315
- mlrun/model_monitoring/application.py +5 -296
- mlrun/model_monitoring/applications/__init__.py +24 -0
- mlrun/model_monitoring/applications/_application_steps.py +157 -0
- mlrun/model_monitoring/applications/base.py +282 -0
- mlrun/model_monitoring/applications/context.py +214 -0
- mlrun/model_monitoring/applications/evidently_base.py +211 -0
- mlrun/model_monitoring/applications/histogram_data_drift.py +349 -0
- mlrun/model_monitoring/applications/results.py +99 -0
- mlrun/model_monitoring/controller.py +104 -84
- mlrun/model_monitoring/controller_handler.py +13 -5
- mlrun/model_monitoring/db/__init__.py +18 -0
- mlrun/model_monitoring/{stores → db/stores}/__init__.py +43 -36
- mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
- mlrun/model_monitoring/{stores/model_endpoint_store.py → db/stores/base/store.py} +64 -40
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
- mlrun/model_monitoring/{stores → db/stores/sqldb}/models/base.py +109 -5
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +88 -0
- mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +684 -0
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
- mlrun/model_monitoring/{stores/kv_model_endpoint_store.py → db/stores/v3io_kv/kv_store.py} +310 -165
- mlrun/model_monitoring/db/tsdb/__init__.py +100 -0
- mlrun/model_monitoring/db/tsdb/base.py +329 -0
- mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
- mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +240 -0
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +45 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +397 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +117 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +630 -0
- mlrun/model_monitoring/evidently_application.py +6 -118
- mlrun/model_monitoring/features_drift_table.py +134 -106
- mlrun/model_monitoring/helpers.py +127 -28
- mlrun/model_monitoring/metrics/__init__.py +13 -0
- mlrun/model_monitoring/metrics/histogram_distance.py +127 -0
- mlrun/model_monitoring/model_endpoint.py +3 -2
- mlrun/model_monitoring/prometheus.py +1 -4
- mlrun/model_monitoring/stream_processing.py +62 -231
- mlrun/model_monitoring/tracking_policy.py +9 -2
- mlrun/model_monitoring/writer.py +152 -124
- mlrun/package/__init__.py +6 -6
- mlrun/package/context_handler.py +5 -5
- mlrun/package/packager.py +7 -7
- mlrun/package/packagers/default_packager.py +6 -6
- mlrun/package/packagers/numpy_packagers.py +15 -15
- mlrun/package/packagers/pandas_packagers.py +5 -5
- mlrun/package/packagers/python_standard_library_packagers.py +10 -10
- mlrun/package/packagers_manager.py +19 -23
- mlrun/package/utils/_formatter.py +6 -6
- mlrun/package/utils/_pickler.py +2 -2
- mlrun/package/utils/_supported_format.py +4 -4
- mlrun/package/utils/log_hint_utils.py +2 -2
- mlrun/package/utils/type_hint_utils.py +4 -9
- mlrun/platforms/__init__.py +11 -10
- mlrun/platforms/iguazio.py +24 -203
- mlrun/projects/operations.py +35 -21
- mlrun/projects/pipelines.py +68 -99
- mlrun/projects/project.py +830 -266
- mlrun/render.py +3 -11
- mlrun/run.py +162 -166
- mlrun/runtimes/__init__.py +62 -7
- mlrun/runtimes/base.py +39 -32
- mlrun/runtimes/daskjob.py +8 -8
- mlrun/runtimes/databricks_job/databricks_cancel_task.py +1 -1
- mlrun/runtimes/databricks_job/databricks_runtime.py +7 -7
- mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
- mlrun/runtimes/funcdoc.py +0 -28
- mlrun/runtimes/function_reference.py +1 -1
- mlrun/runtimes/kubejob.py +28 -122
- mlrun/runtimes/local.py +6 -3
- mlrun/runtimes/mpijob/__init__.py +0 -20
- mlrun/runtimes/mpijob/abstract.py +9 -10
- mlrun/runtimes/mpijob/v1.py +1 -1
- mlrun/{model_monitoring/stores/models/sqlite.py → runtimes/nuclio/__init__.py} +7 -9
- mlrun/runtimes/nuclio/api_gateway.py +709 -0
- mlrun/runtimes/nuclio/application/__init__.py +15 -0
- mlrun/runtimes/nuclio/application/application.py +523 -0
- mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
- mlrun/runtimes/{function.py → nuclio/function.py} +112 -73
- mlrun/runtimes/{nuclio.py → nuclio/nuclio.py} +6 -6
- mlrun/runtimes/{serving.py → nuclio/serving.py} +45 -51
- mlrun/runtimes/pod.py +286 -88
- mlrun/runtimes/remotesparkjob.py +2 -2
- mlrun/runtimes/sparkjob/spark3job.py +51 -34
- mlrun/runtimes/utils.py +7 -75
- mlrun/secrets.py +9 -5
- mlrun/serving/remote.py +2 -7
- mlrun/serving/routers.py +13 -10
- mlrun/serving/server.py +22 -26
- mlrun/serving/states.py +99 -25
- mlrun/serving/utils.py +3 -3
- mlrun/serving/v1_serving.py +6 -7
- mlrun/serving/v2_serving.py +59 -20
- mlrun/track/tracker.py +2 -1
- mlrun/track/tracker_manager.py +3 -3
- mlrun/track/trackers/mlflow_tracker.py +1 -2
- mlrun/utils/async_http.py +5 -7
- mlrun/utils/azure_vault.py +1 -1
- mlrun/utils/clones.py +1 -2
- mlrun/utils/condition_evaluator.py +3 -3
- mlrun/utils/db.py +3 -3
- mlrun/utils/helpers.py +183 -197
- mlrun/utils/http.py +2 -5
- mlrun/utils/logger.py +76 -14
- mlrun/utils/notifications/notification/__init__.py +17 -12
- mlrun/utils/notifications/notification/base.py +14 -2
- mlrun/utils/notifications/notification/console.py +2 -0
- mlrun/utils/notifications/notification/git.py +3 -1
- mlrun/utils/notifications/notification/ipython.py +3 -1
- mlrun/utils/notifications/notification/slack.py +101 -21
- mlrun/utils/notifications/notification/webhook.py +11 -1
- mlrun/utils/notifications/notification_pusher.py +155 -30
- mlrun/utils/retryer.py +208 -0
- mlrun/utils/singleton.py +1 -1
- mlrun/utils/v3io_clients.py +2 -4
- mlrun/utils/version/version.json +2 -2
- mlrun/utils/version/version.py +2 -6
- {mlrun-1.6.4rc2.dist-info → mlrun-1.7.0rc20.dist-info}/METADATA +31 -19
- mlrun-1.7.0rc20.dist-info/RECORD +353 -0
- mlrun/kfpops.py +0 -868
- mlrun/model_monitoring/batch.py +0 -1095
- mlrun/model_monitoring/stores/models/__init__.py +0 -27
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -384
- mlrun/platforms/other.py +0 -306
- mlrun-1.6.4rc2.dist-info/RECORD +0 -314
- {mlrun-1.6.4rc2.dist-info → mlrun-1.7.0rc20.dist-info}/LICENSE +0 -0
- {mlrun-1.6.4rc2.dist-info → mlrun-1.7.0rc20.dist-info}/WHEEL +0 -0
- {mlrun-1.6.4rc2.dist-info → mlrun-1.7.0rc20.dist-info}/entry_points.txt +0 -0
- {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
|
|
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
|
|
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
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
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
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
if stream_path.startswith("kafka://") or
|
|
1480
|
-
topic,
|
|
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
|
-
|
|
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)
|
mlrun/serving/v1_serving.py
CHANGED
|
@@ -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:
|
|
99
|
+
def preprocess(self, request: dict) -> dict:
|
|
101
100
|
return request
|
|
102
101
|
|
|
103
|
-
def postprocess(self, request:
|
|
102
|
+
def postprocess(self, request: dict) -> dict:
|
|
104
103
|
return request
|
|
105
104
|
|
|
106
|
-
def predict(self, request:
|
|
105
|
+
def predict(self, request: dict) -> dict:
|
|
107
106
|
raise NotImplementedError()
|
|
108
107
|
|
|
109
|
-
def explain(self, request:
|
|
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:
|
|
202
|
+
def __init__(self, models: dict, server: _ServerInfo = None):
|
|
204
203
|
self.models = models
|
|
205
204
|
self.srvinfo = server
|
|
206
205
|
self.context = None
|
mlrun/serving/v2_serving.py
CHANGED
|
@@ -15,12 +15,13 @@
|
|
|
15
15
|
import threading
|
|
16
16
|
import time
|
|
17
17
|
import traceback
|
|
18
|
-
from typing import
|
|
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=
|
|
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[
|
|
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=
|
|
179
|
+
model_file, extra_data = self.get_model(suffix=".pkl")
|
|
181
180
|
self.model = load(open(model_file, "rb"))
|
|
182
|
-
categories = extra_data[
|
|
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
|
|
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:
|
|
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:
|
|
375
|
+
def postprocess(self, request: dict) -> dict:
|
|
370
376
|
"""postprocess, before returning response"""
|
|
371
377
|
return request
|
|
372
378
|
|
|
373
|
-
def predict(self, request:
|
|
379
|
+
def predict(self, request: dict) -> dict:
|
|
374
380
|
"""model prediction operation"""
|
|
375
381
|
raise NotImplementedError()
|
|
376
382
|
|
|
377
|
-
def explain(self, request:
|
|
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.
|
|
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(
|
|
36
|
+
def is_enabled() -> bool:
|
|
36
37
|
"""
|
|
37
38
|
Checks if tracker is enabled.
|
|
38
39
|
|
mlrun/track/tracker_manager.py
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import importlib
|
|
16
16
|
import inspect
|
|
17
|
-
from typing import
|
|
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:
|
|
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:
|
|
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) ->
|
|
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
|
|
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:
|
|
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[
|
|
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:
|
|
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:
|
|
118
|
+
blacklisted_methods: list[str],
|
|
121
119
|
*args,
|
|
122
120
|
**kwargs,
|
|
123
121
|
):
|
mlrun/utils/azure_vault.py
CHANGED
|
@@ -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
|
|
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) ->
|
|
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:
|
|
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:
|
|
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:
|
|
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)
|